Skip to content

Data table

useDataTable wraps TanStack Table and pairs with DataTable, which renders the instance over the stock Table primitives. Columns are TanStack ColumnDefs — shadcn’s data-table guide applies directly.

For ordinary app tables, pass columns and rows; sorting, filtering, and pagination run in the browser:

import {
useDataTable, DataTable, DataTableColumnHeader, DataTablePagination,
type ColumnDef,
} from "@lodekit/ui";
type Run = { task: string; state: string; durationMs: number };
const columns: ColumnDef<Run>[] = [
{
accessorKey: "task",
header: ({ column }) => <DataTableColumnHeader column={column} title="Task" />,
},
{ accessorKey: "state", header: "State" },
{
accessorKey: "durationMs",
header: ({ column }) => <DataTableColumnHeader column={column} title="Duration" />,
},
];
export function RunsTable({ runs }: { runs: Run[] }) {
const table = useDataTable({
columns,
data: runs,
initialState: { pagination: { pageSize: 10 } },
});
return (
<>
<DataTable table={table} />
<DataTablePagination table={table} />
</>
);
}

With manual: true, the table stops computing anything itself: sorting, filtering, and pagination become state you own. Interactions call your on*Change callbacks; you execute the query (typically SQL via a server function) and pass the resulting page back as data. Multi-column sorting state is the standard TanStack shape, [{ id, desc }].

import { useState } from "react";
import { useDataTable, type SortingState } from "@lodekit/ui";
const [sorting, setSorting] = useState<SortingState>([]);
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 25 });
// Re-query whenever sorting/pagination change; ORDER BY from `sorting`,
// LIMIT/OFFSET from `pagination`. `rows` and `total` come from the server.
const table = useDataTable({
columns,
data: rows,
manual: true,
rowCount: total,
state: { sorting, pagination },
onSortingChange: setSorting,
onPaginationChange: setPagination,
});

Manual mode requires rowCount (or pageCount) so the pager can do its math. Everything else — DataTable, DataTableColumnHeader, DataTablePagination — works unchanged.

  • DataTableColumnHeader — drop into a column’s header to get a sort toggle (asc/desc/hide) that reflects sort state.
  • DataTablePagination — page-size select and first/prev/next/last controls; takes an optional pageSizeOptions array.
  • DataTableViewOptions — a column-visibility dropdown for the toolbar.
  • DataTableFacetedFilter — a multi-select filter with per-value counts (client mode only — the counts come from client-side faceting).

The Greenhouse showcase renders one: the care-history table on the Almanac page.