DataTable
An opinionated table with sorting, pagination, filtering, row selection, and column visibility built on @tanstack/react-table and Wuko's Table primitive. Pass typed columns and data, opt into features with props. For full control, see Building your own at the bottom of this page.
Installation
npx shadcn@latest add @wuko/data-tableUsage
Pass a columns array and data array. Column definitions follow TanStack Table's API.
| Device | Region | Status | Firmware |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | 2.4.1 |
| KIOSK-3310 | us-east | updating | 2.4.0 |
| KIOSK-3300 | us-west | offline | 2.4.1 |
| KIOSK-2150 | eu-north | healthy | 2.4.1 |
| KIOSK-2199 | eu-north | degraded | 2.4.0 |
Sorting
Use the SortableHeader helper inside a column's header function to make a column sortable. Clicking the header toggles ascending, descending, and unsorted.
| Device | Region | Firmware | |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | 2.4.1 |
| KIOSK-3310 | us-east | updating | 2.4.0 |
| KIOSK-3300 | us-west | offline | 2.4.1 |
| KIOSK-2150 | eu-north | healthy | 2.4.1 |
| KIOSK-2199 | eu-north | degraded | 2.4.0 |
import { SortableHeader } from "@/components/ui/data-table";
const columns: ColumnDef<Device>[] = [
{ accessorKey: "id", header: "Device" },
{
accessorKey: "status",
header: ({ column }) => (
<SortableHeader column={column}>Status</SortableHeader>
),
},
];Pagination
Pagination is built in. Pass pageSize to control rows per page. The footer shows the current range and total count, with previous/next buttons.
| Device | Region | Status | Firmware |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | 2.4.1 |
| KIOSK-3310 | us-east | updating | 2.4.0 |
| KIOSK-3300 | us-west | offline | 2.4.1 |
<DataTable
columns={columns}
data={data}
pageSize={10}
/>Filtering
Pass filterColumn with the accessorKey of the column to filter on. A search input renders above the table. Filtering happens client-side via TanStack's getFilteredRowModel.
| Device | Region | Status | Firmware |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | 2.4.1 |
| KIOSK-3310 | us-east | updating | 2.4.0 |
| KIOSK-3300 | us-west | offline | 2.4.1 |
| KIOSK-2150 | eu-north | healthy | 2.4.1 |
| KIOSK-2199 | eu-north | degraded | 2.4.0 |
<DataTable
columns={columns}
data={data}
filterColumn="region"
filterPlaceholder="Filter by region..."
/>Row selection
Add a column with id: "select" rendering a Checkbox in both header and cell to enable row selection. The selected count appears in the footer. Selected rows get a subtle accent background.
| Device | Region | Status | |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | |
| KIOSK-3310 | us-east | updating | |
| KIOSK-3300 | us-west | offline | |
| KIOSK-2150 | eu-north | healthy | |
| KIOSK-2199 | eu-north | degraded |
Column visibility
Pass enableColumnVisibility to add a Columns dropdown in the header bar. Users can toggle individual columns on or off without losing data.
| Device | Region | Status | Firmware |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | 2.4.1 |
| KIOSK-3310 | us-east | updating | 2.4.0 |
| KIOSK-3300 | us-west | offline | 2.4.1 |
| KIOSK-2150 | eu-north | healthy | 2.4.1 |
| KIOSK-2199 | eu-north | degraded | 2.4.0 |
<DataTable
columns={columns}
data={data}
enableColumnVisibility
/>Row actions
Add a column with a kebab icon trigger and DropdownMenu to provide per-row actions like view, edit, or delete. Set enableSorting: false on the action column.
| Device | Region | Status | |
|---|---|---|---|
| KIOSK-4729 | us-west | healthy | |
| KIOSK-3310 | us-east | updating | |
| KIOSK-3300 | us-west | offline | |
| KIOSK-2150 | eu-north | healthy | |
| KIOSK-2199 | eu-north | degraded |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| columns | ColumnDef<TData, TValue>[] | — | Required. Array of column definitions from @tanstack/react-table. Each column needs an accessorKey or accessorFn and a header. |
| data | TData[] | — | Required. Array of row objects to display. |
| pageSize | number | 10 | Number of rows per page when pagination is enabled. |
| filterColumn | string | — | Column accessorKey to filter on. When set, a search input renders above the table. |
| filterPlaceholder | string | "Filter..." | Placeholder text for the filter input. |
| enableColumnVisibility | boolean | false | When true, renders a Columns dropdown menu in the header bar for toggling column visibility. |
Building your own
Wuko's DataTable is opinionated. If you need different behavior — server-side pagination, custom filter UI, row expansion, virtualized rows, or anything else — compose your own using Table and useReactTable directly. The DataTable source is a useful starting point.
For more advanced patterns, see TanStack Table's documentation.
Accessibility
- Built on the Table primitive, which renders native HTML table elements. Screen readers announce row and column counts and header relationships.
- Sortable column headers are rendered as buttons inside the
<th>. The sort state is exposed via TanStack's column API; consumers can addaria-sortfor additional screen reader support. - Selection checkboxes use the Wuko Checkbox primitive, which supports indeterminate state for the "some rows selected" header.
- Column visibility dropdown is keyboard-navigable via the underlying DropdownMenu primitive (Tab, Arrow keys, Esc).
- Pagination controls are buttons with appropriate disabled states when on the first or last page. The current page range and selected count announce changes for screen readers.