Blocks

Data Table

Sort, filter, and select rows in an inset table. Compose the toolbar and footer around your data.

Installation

pnpm dlx @mielui/svelte add data-table

With Vite SSR, keep the v9.2.4 Svelte adapter in the bundled dependencies so Node can resolve its Svelte module imports.

export default defineConfig({
    ssr: {
        noExternal: ['@tanstack/svelte-table']
    }
});

Create your table

DataTable accepts a table created by @tanstack/svelte-table 9.2.4. Use v9 createTable and tableFeatures; v8 createSvelteTable examples use a different API. Register only the features and row models your table needs. Mielui renders that instance and never copies its data or owns a second sorting, filtering, selection, or pagination state.

import {
    type DataTableFilterDefinition,
    dataTableFilter
} from '@mielui/svelte/components/data-table';
import {
    type ColumnDef,
    columnFilteringFeature,
    columnVisibilityFeature,
    createFilteredRowModel,
    createPaginatedRowModel,
    createSortedRowModel,
    filterFns,
    rowPaginationFeature,
    rowSelectionFeature,
    rowSortingFeature,
    sortFns,
    tableFeatures
} from '@tanstack/svelte-table';

export type Member = {
    id: string;
    name: string;
    email: string;
    role: string;
    projects: number;
    joined: string;
};
export const features = tableFeatures({
    columnFilteringFeature,
    columnVisibilityFeature,
    rowPaginationFeature,
    rowSelectionFeature,
    rowSortingFeature,
    filteredRowModel: createFilteredRowModel(),
    sortedRowModel: createSortedRowModel(),
    paginatedRowModel: createPaginatedRowModel(),
    filterFns,
    sortFns
});
export const columns: ColumnDef<typeof features, Member>[] = [
    { accessorKey: 'name', header: 'Name', filterFn: 'includesString' },
    { accessorKey: 'email', header: 'Email', filterFn: dataTableFilter },
    { accessorKey: 'role', header: 'Role', filterFn: dataTableFilter },
    { accessorKey: 'projects', header: 'Projects', filterFn: dataTableFilter },
    { accessorKey: 'joined', header: 'Joined', filterFn: dataTableFilter }
];
export const members: Member[] = [
    {
        id: 'm-01',
        joined: '2026-01-15',
        name: 'Maya Chen',
        email: 'maya@acme.test',
        role: 'Owner',
        projects: 12
    },
    {
        id: 'm-02',
        joined: '2026-02-15',
        name: 'Theo Martin',
        email: 'theo@acme.test',
        role: 'Editor',
        projects: 8
    },
    {
        id: 'm-03',
        joined: '2026-03-15',
        name: 'Amira Diallo',
        email: 'amira@acme.test',
        role: 'Editor',
        projects: 6
    },
    {
        id: 'm-04',
        joined: '2026-04-15',
        name: 'Noah Kim',
        email: 'noah@acme.test',
        role: 'Viewer',
        projects: 3
    },
    {
        id: 'm-05',
        joined: '2026-05-15',
        name: 'Luca Rossi',
        email: 'luca@acme.test',
        role: 'Editor',
        projects: 7
    },
    {
        id: 'm-06',
        joined: '2026-06-15',
        name: 'Sofia Costa',
        email: 'sofia@acme.test',
        role: 'Viewer',
        projects: 2
    },
    {
        id: 'm-07',
        joined: '2026-07-15',
        name: 'Eva Novak',
        email: 'eva@acme.test',
        role: 'Editor',
        projects: 9
    },
    {
        id: 'm-08',
        joined: '2026-08-15',
        name: 'Oscar Anders',
        email: 'oscar@acme.test',
        role: 'Viewer',
        projects: 4
    }
];

export const filters: DataTableFilterDefinition[] = [
    {
        column: 'role',
        label: 'Role',
        type: 'select',
        options: [
            { value: 'Owner', label: 'Owner' },
            { value: 'Editor', label: 'Editor' },
            { value: 'Viewer', label: 'Viewer' }
        ]
    },
    { column: 'projects', label: 'Projects', type: 'number', min: 0, step: 1 },
    { column: 'joined', label: 'Joined', type: 'date' },
    { column: 'email', label: 'Email', type: 'text', placeholder: 'company.test' }
];

Compose each region

Root without children renders View, Summary, and Pagination. The same public parts build custom layouts: move Summary into Toolbar, omit pagination, or place controls before and after View. Root's children snippet receives table, rows, total, and selected. Summary exposes the same data through its children snippet. Toolbar is a layout container, not an extra keyboard toolbar.

View renders Mielui Table parts. To arrange the table yourself, place DataTable.Header and DataTable.Body inside Table.Root. Header supports grouped columns, and Body respects column visibility when that feature is installed.

Header and cell snippets receive the original TanStack objects. Use FlexRender for column definitions or renderSnippet for Svelte snippets within them. Empty accepts loading and spans the visible columns in a single row.

ColumnHeader is a button. Each click moves the column to its next sort state: ascending, descending, then unsorted. An arrow shows the current direction, a tooltip names what the next click does, and sorted headers expose aria-sort. Hold Shift while clicking to add the column to a multi-column sort. Sort provides a separate field-and-direction menu, with checked radio choices. Pass its columns prop to control available fields and labels. Sorting, pagination, and selection parts disappear or disable themselves when their corresponding TanStack feature is absent. Provide a meaningful caption for the table.

Search and filter

Place Filter inside Filters to join the search input and Filter button with Group. The optional children snippet renders before the button. Active facets and Reset stay outside that group. Omit children for a standalone filter picker. The picker stays visible and disables itself when every available filter is shown.

Filter searches a string column such as name with includesString. Filters accepts definitions with column, label, and type: text, select, number, or date. Choosing a field adds its chip and opens the editor.

Select definitions need value/label options and can accept multiple choices. Number definitions accept min, max, and step. Date editors use DatePicker. Place these controls with Sort inside Toolbar.

Register dataTableFilter as each facet column's filterFn. Facets store a DataTableFilterClause in TanStack's columnFilters state, containing type, operator, and value.

Text clauses support contains, equals, and not. Select clauses support in and notIn. Number and date clauses support equals, lt, lte, gt, gte, and inclusive between bounds. Built-in editors offer common comparisons; custom editors can use the complete clause type.

Text matching ignores case. Numeric cells must contain numbers, and date cells must use ISO calendar-date strings. Empty bounds stay open. These filters run on the client. Validate saved filters and translate them into your own backend queries for server filtering.

Facet is independently composable with table and filter props, bind:open, onOpenChange, and onRemove. A definition's editor snippet receives value and setValue for a custom control using your column's filterFn. Remove filter clears that column. Filters' Reset clears and hides its configured facets while leaving the separate search input alone. All filters combine through TanStack's filtering state; no second filter store is owned by Mielui.

Own the state and layout

Use reactive data getters when rows can change. TanStack's createTableState supports controlled state slices; pair each controlled slice with its change callback. Table atoms and methods participate in Svelte reactivity. This composition reorders its summary and omits pagination.

Selection and stable identity

Set selectable on Root or View to add a selection column. Register rowSelectionFeature and give getRowId a stable record ID. Index-based IDs can select the wrong record when data changes.

The header checkbox selects the current page's selectable rows and shows a mixed state for partial selection. Use rowLabel to give each checkbox a readable name.

Selection can persist across filters and pages. Summary reports selected IDs separately from the current row total. With server pagination, some selected records may not be loaded on the current page.

Selection is also an exported checkbox part for custom columns. It accepts checked, indeterminate, disabled, label, and onCheckedChange. For grouping or tree rows, compose your own selection controls using TanStack's row-selection APIs and the required parent/child policy.

Empty and loading states

loading marks the root/table busy and disables pagination. Existing rows remain visible during refresh; an empty loading table shows a status message. Override the empty snippet for an explanation or recovery action. Error messages and retry policies remain application-owned.

Server data

For server filtering, sorting, or pagination, enable the corresponding TanStack manual options and pass returned rows through a reactive data getter. Supply rowCount or pageCount when known. Use pageCount=-1 to keep Next available when the last page is unknown.

Handle request cancellation, URL state, and errors in your application. DataTable does not fetch or virtualize rows. Use pagination for large lists.

Inset layout

Set variant="inset" on Root to frame the table with its footer. Toolbar floats above the frame as plain controls, wherever you place it inside Root. Place Summary and Pagination in a div with data-ui="data-table-footer" for the strip under the table. Column headings and that footer sit on the white frame, and the rows sit on the recessed surface between them. The children snippet lets you omit the toolbar, reorder controls, or replace cells. Pagination uses the shared Pagination component for known page counts.

Labels

Built-in text is English. Pass a DataTableLabels object to labels on Root to translate or reword the empty and loading rows, the summary, pagination, sorting and the filter editors and the filter button summaries. Text that depends on a count or a name is a function that returns the whole phrase, so a translation can place the number anywhere: rows receives the row count and selected receives the selected and total counts. Every key is optional, and an omitted key keeps its English default.

<script lang="ts">
    import * as DataTable from '@mielui/svelte/components/data-table';
    import type { DataTableLabels } from '@mielui/svelte/components/data-table';

    const labels: DataTableLabels = {
        empty: 'Aucun rรฉsultat.',
        loading: 'Chargementโ€ฆ',
        rows: (count) => (count === 1 ? '1 ligne' : `${count} lignes`),
        selected: (selected, total) => `${selected} sur ${total} sรฉlectionnรฉes`,
        selectPage: 'Sรฉlectionner les lignes de la page',
        summarySelected: (count) => `${count} choisies`,
        sort: 'Trier',
        previous: 'Prรฉcรฉdent',
        next: 'Suivant'
    };
</script>

<DataTable.Root {table} {labels} />

API reference

DataTable.Root

  • cell
    Snippet<[Cell<TableFeatures, RowData, unknown>]>

    Renders a cell. Defaults to the column's cell definition.

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • loading
    boolean

    Shows the loading state in place of the content.

    Default false

  • caption
    string

    Accessible caption that describes the table.

  • header
    Snippet<[Header<TableFeatures, RowData, unknown>]>

    Renders a column header.

  • selectable
    boolean

    Adds a selection checkbox column.

    Default false

  • rowLabel
    ((row: Row<TableFeatures, RowData>) => string)

    Returns a row's name, used in its selection checkbox's accessible name.

  • empty
    Snippet<[{ loading: boolean; }]>

    Content shown when there are no rows. It receives the loading state.

  • variant
    "default" | "inset"

    Both variants draw the rows in an inset table. default leaves the toolbar and footer outside it. inset puts the table and its footer in one frame, with the Toolbar above.

    Default 'default'

  • labels
    DataTableLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

  • children
    Snippet<[DataTableState<TableFeatures, RowData>]>

    Content rendered inside.

DataTable.Body

  • cell
    Snippet<[Cell<TableFeatures, RowData, unknown>]>

    Renders a cell. Defaults to the column's cell definition.

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • loading
    boolean

    Shows the loading state in place of the content.

    Default false

  • selectable
    boolean

    Adds a selection checkbox column.

    Default false

  • rowLabel
    ((row: Row<TableFeatures, RowData>) => string)

    Returns a row's name, used in its selection checkbox's accessible name.

  • empty
    Snippet<[{ loading: boolean; }]>

    Content shown when there are no rows. It receives the loading state.

DataTable.Empty

  • class
    string

    Classes added to the element.

  • columns Required
    number

    Number of columns the empty row spans.

  • loading
    boolean

    Shows the loading state in place of the content.

    Default false

  • children
    Snippet<[{ loading: boolean; }]>

    Content rendered inside.

DataTable.Filter

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • column Required
    string

    Id of the column the search field filters.

  • label Required
    string

    Accessible name of the control.

DataTable.Header

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • header
    Snippet<[Header<TableFeatures, RowData, unknown>]>

    Renders a column header.

  • selectable
    boolean

    Adds a selection checkbox column.

    Default false

DataTable.Pagination

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • loading
    boolean

    Shows the loading state in place of the content.

    Default false

DataTable.Selection

  • class
    string

    Classes added to the element.

  • checked
    boolean

    Whether the checkbox is checked.

    Default false

  • indeterminate
    boolean

    Shows the mixed state when only some rows are selected.

    Default false

  • disabled
    boolean

    Disables the checkbox.

    Default false

  • label Required
    string

    Accessible name of the control.

  • onCheckedChange Required
    (checked: boolean) => void

    Called with the new state when the checkbox changes.

DataTable.Summary

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • children
    Snippet<[DataTableState<TableFeatures, RowData>]>

    Content rendered inside.

DataTable.View

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • loading
    boolean

    Shows the loading state in place of the content.

    Default false

  • selectable
    boolean

    Adds a selection checkbox column.

    Default false

  • caption
    string

    Accessible caption that describes the table.

  • rowLabel
    ((row: Row<TableFeatures, RowData>) => string)

    Returns a row's name, used in its selection checkbox's accessible name.

  • header
    Snippet<[Header<TableFeatures, RowData, unknown>]>

    Renders a column header.

  • cell
    Snippet<[Cell<TableFeatures, RowData, unknown>]>

    Renders a cell. Defaults to the column's cell definition.

  • empty
    Snippet<[{ loading: boolean; }]>

    Content shown when there are no rows. It receives the loading state.

DataTable.ColumnHeader

  • header Required
    Header_Core<TableFeatures, RowData, unknown> & Header_ColumnResizing & Header_ColumnSizing

    TanStack header to render.

  • class
    string

    Classes added to the element.

DataTable.Facet

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • filter Required
    { column: string; label: string; editor?: Snippet<[{ value: unknown; setValue: (value: unknown) => void; }]> | undefined; } & ({ type: "text"; placeholder?: string | undefined; } | { type: "select"; options: readonly { value: string; label: string; }[]; } | { type: "number"; min?: number | undefined; max?: number | undefined; step?: number | undefined; } | { type: "date"; })

    Filter definition this chip edits.

  • open Bindable
    boolean

    Whether it is open. Bind it to control the state from outside.

    Default false

  • onOpenChange
    ((open: boolean) => void)

    Called with the new state whenever it opens or closes.

  • onRemove
    (() => void)

    Called when the filter is removed.

  • class
    string

    Classes added to the element.

DataTable.Filters

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • filters Required
    readonly DataTableFilterDefinition[]

    Filters offered in the Filter menu.

  • children
    Snippet<[]>

    Content rendered inside.

  • class
    string

    Classes added to the element.

DataTable.Sort

  • table Required
    Table_Core<TableFeatures, RowData> & Table_CellSelection<TableFeatures, RowData> & Table_CellSpanning<TableFeatures, RowData> & Table_ColumnFaceting<TableFeatures, RowData> & Table_ColumnFiltering & Table_ColumnGrouping<TableFeatures, RowData> & Table_ColumnOrdering<TableFeatures, RowData> & Table_ColumnPinning<TableFeatures, RowData> & Table_ColumnResizing & Table_ColumnSizing & Table_ColumnVisibility<TableFeatures, RowData> & Table_GlobalFiltering<TableFeatures, RowData> & Table_RowExpanding<TableFeatures, RowData> & Table_RowPagination<TableFeatures, RowData> & Table_RowPinning<TableFeatures, RowData> & Table_RowSelection<TableFeatures, RowData> & Table_RowSorting<TableFeatures, RowData>

    TanStack Table instance that drives the table.

  • columns
    readonly { id: string; label: string; }[]

    Columns offered in the Sort menu.

  • class
    string

    Classes added to the element.

Other parts

These parts have no props of their own. They pass HTML attributes and events to their element.

  • DataTable.Toolbar