Studio
2

Data Table

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 offers explicit ascending, descending, and clear-sort choices; sorted headers expose aria-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 group filters, the table, and pagination in one frame. Toolbar stays in the top strip, followed by the column headings and rows. Place Summary and Pagination in a div with data-ui="data-table-footer" for the bottom strip. The children snippet lets you omit the toolbar, reorder controls, or replace cells. Pagination uses the shared Pagination component for known page counts.

API reference

DataTable.Root

Prop Type Default
cell Snippet<[Cell<TableFeatures, RowData, unknown>]> | undefined —
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> —
loading boolean | undefined false
caption string | undefined —
header Snippet<[Header<TableFeatures, RowData, unknown>]> | undefined —
selectable boolean | undefined false
rowLabel ((row: Row<TableFeatures, RowData>) => string) | undefined —
empty Snippet<[{ loading: boolean; }]> | undefined —
variant "inset" | "default" | undefined 'default'
children Snippet<[DataTableState<TableFeatures, RowData>]> | undefined —

DataTable.Body

Prop Type Default
cell Snippet<[Cell<TableFeatures, RowData, unknown>]> | undefined —
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> —
loading boolean | undefined false
selectable boolean | undefined false
rowLabel ((row: Row<TableFeatures, RowData>) => string) | undefined —
empty Snippet<[{ loading: boolean; }]> | undefined —

DataTable.Empty

Prop Type Default
class string | undefined —
columns Required number —
loading boolean | undefined false
children Snippet<[{ loading: boolean; }]> | undefined —

DataTable.Filter

Prop Type Default
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> —
column Required string —
label Required string —

DataTable.Header

Prop Type Default
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> —
header Snippet<[Header<TableFeatures, RowData, unknown>]> | undefined —
selectable boolean | undefined false

DataTable.Pagination

Prop Type Default
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> —
loading boolean | undefined false

DataTable.Selection

Prop Type Default
class string | undefined —
checked boolean | undefined false
indeterminate boolean | undefined false
disabled boolean | undefined false
label Required string —
onCheckedChange Required (checked: boolean) => void —

DataTable.Summary

Prop Type Default
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> —
children Snippet<[DataTableState<TableFeatures, RowData>]> | undefined —

DataTable.Toolbar

DataTable.View

Prop Type Default
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> —
loading boolean | undefined false
selectable boolean | undefined false
caption string | undefined —
rowLabel ((row: Row<TableFeatures, RowData>) => string) | undefined —
header Snippet<[Header<TableFeatures, RowData, unknown>]> | undefined —
cell Snippet<[Cell<TableFeatures, RowData, unknown>]> | undefined —
empty Snippet<[{ loading: boolean; }]> | undefined —

DataTable.ColumnHeader

Prop Type Default
header Required Header_Core<TableFeatures, RowData, unknown> & Header_ColumnResizing & Header_ColumnSizing —
class string | undefined —

DataTable.Facet

Prop Type Default
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> —
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"; }) —
open Bindable boolean | undefined false
onOpenChange ((open: boolean) => void) | undefined —
onRemove (() => void) | undefined —
class string | undefined —

DataTable.Filters

Prop Type Default
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> —
filters Required readonly DataTableFilterDefinition[] —
children Snippet<[]> | undefined —
class string | undefined —

DataTable.Sort

Prop Type Default
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> —
columns readonly { id: string; label: string; }[] | undefined —
class string | undefined —