Skip to content
  • System
  • Light
  • Dark
  • High contrast

DataTable

1.1.1Non-text ContentApass
1.2.1Audio-only and Video-onlyAtodo
1.2.2Captions (Prerecorded)Afail
1.3.1Info and RelationshipsApass
1.3.2Meaningful SequenceApass
1.4.1Use of ColorAtodo
1.4.3Contrast (Minimum)AApass
2.1.1KeyboardApass
import { DataTable } from '@eekodigital/raster/data-table';
import type { DataTableColumnDef } from '@eekodigital/raster/data-table';

type Row = { id: string; name: string; status: string };

const columns: DataTableColumnDef<Row>[] = [
  { accessorKey: 'ref', header: 'Ref' },
  { accessorKey: 'name', header: 'Name' },
  { accessorKey: 'status', header: 'Status' },
];

<DataTable columns={columns} data={rows} />

All columns are sortable by default. Click a header to sort ascending, click again for descending, click a third time to clear. Hold Shift to sort by multiple columns simultaneously.

1.1.1Non-text ContentApass
1.2.1Audio-only and Video-onlyAtodo
1.2.2Captions (Prerecorded)Afail
1.3.1Info and RelationshipsApass
1.3.2Meaningful SequenceApass
1.4.1Use of ColorAtodo
1.4.3Contrast (Minimum)AApass
2.1.1KeyboardApass
// All columns are sortable — no extra config needed.
// Shift+click a second header to add a secondary sort.
<DataTable columns={columns} data={rows} />

Pass pageSize to enable built-in pagination. Previous/next controls appear below the table when the data exceeds one page.

1.1.1Non-text ContentApass
1.2.1Audio-only and Video-onlyAtodo
1.2.2Captions (Prerecorded)Afail
Page 1 of 3
<DataTable columns={columns} data={rows} pageSize={3} />

Add filter to show a search input above the table that filters across all column values simultaneously. Use filterPlaceholder to customise the input text.

1.1.1Non-text ContentApass
1.2.1Audio-only and Video-onlyAtodo
1.2.2Captions (Prerecorded)Afail
1.3.1Info and RelationshipsApass
1.3.2Meaningful SequenceApass
1.4.1Use of ColorAtodo
1.4.3Contrast (Minimum)AApass
2.1.1KeyboardApass
<DataTable columns={columns} data={rows} filter />

Add resizable to enable drag handles on column borders. Individual columns can opt out by setting enableResizing: false in their column definition.

1.1.1Non-text ContentApass
1.2.1Audio-only and Video-onlyAtodo
1.2.2Captions (Prerecorded)Afail
1.3.1Info and RelationshipsApass
1.3.2Meaningful SequenceApass
1.4.1Use of ColorAtodo
1.4.3Contrast (Minimum)AApass
2.1.1KeyboardApass
<DataTable columns={columns} data={rows} resizable />

Pass pinnedColumns to keep columns sticky at the left or right edge while the table scrolls horizontally. Use column id or accessorKey to identify which columns to pin. Set explicit size values in your column definitions for accurate sticky offsets when multiple columns are pinned.

1.1.1Non-text ContentAPerceivableAll images have alt text2025-01-10pass
1.2.1Audio-only and Video-onlyAPerceivable2025-01-10todo
1.4.3Contrast (Minimum)AAPerceivableButton text fails at 3.2:12025-01-12fail
2.1.1KeyboardAOperableAll interactions keyboard accessible2025-01-11pass
2.4.6Headings and LabelsAAOperable2025-01-11pass
<DataTable
  columns={columns}
  data={rows}
  pinnedColumns={{ left: ['ref'], right: ['status'] }}
/>
WCAG 2.2 criteria
1.1.1Non-text ContentApass
1.2.1Audio-only and Video-onlyAtodo
1.2.2Captions (Prerecorded)Afail
1.3.1Info and RelationshipsApass
1.3.2Meaningful SequenceApass
1.4.1Use of ColorAtodo
1.4.3Contrast (Minimum)AApass
2.1.1KeyboardApass
<DataTable columns={columns} data={rows} caption="WCAG 2.2 criteria" />

Use DataTable when: you need multi-column sorting, pagination, column resizing, or column pinning.

Use Table instead when:

your dataset is small and static — changelogs, pricing grids, blog posts. It renders server-side with zero JavaScript.

Use SummaryList instead when:

you’re displaying key–value pairs rather than rows of comparable records.

PropTypeDefaultDescription
columnsColumnDef<TData>[]

TanStack Table column definitions. Re-exported as DataTableColumnDef for convenience.

dataTData[]Data rows.
captionstring

Optional visible <caption> element for screen readers.

pageSizenumberRows per page. Omit to show all rows without pagination controls.
filterbooleanfalseShow a global filter input above the table. Filters across all column values.
filterPlaceholderstring”Filter…”

Placeholder text for the filter input. Only used when filter is set.

resizablebooleanfalse

Enable drag-to-resize handles on column borders. Individual columns can opt out with enableResizing: false.

pinnedColumns{ left?: string[]; right?: string[] }

Pin columns to the left or right edge during horizontal scroll. Pass column id or accessorKey values.