Data Table
Powerful table with sorting, filtering and pagination.
When to Use
Use Data Table when you need to:
- Display structured tabular data with interactive sorting and filtering
- Enable users to search, paginate, and navigate large datasets
- Support row selection for bulk actions (delete, export, assign)
- Provide column visibility controls so users can customize their view
- Format cells with custom renderers (currency, status badges, actions)
Full Featured
Data table with sorting, filtering, pagination, row selection, and column visibility.
| Status | Amount | |||
|---|---|---|---|---|
success | ken99@example.com | $316.00 | ||
success | abe45@example.com | $242.00 | ||
processing | monserrat44@example.com | $837.00 | ||
success | silas22@example.com | $874.00 | ||
failed | carmella@example.com | $721.00 | ||
pending | jessica@example.com | $456.00 | ||
success | michael@example.com | $623.00 | ||
processing | sarah@example.com | $198.00 |
Basic Table
Simple data table using TanStack Table with column definitions, accessors, and custom cell renderers.
| Status | Amount | |
|---|---|---|
success | ken99@example.com | $316.00 |
success | abe45@example.com | $242.00 |
processing | monserrat44@example.com | $837.00 |
success | silas22@example.com | $874.00 |
failed | carmella@example.com | $721.00 |
Sorting
Click column headers to toggle ascending and descending sort order.
success | ken99@example.com | $316.00 |
success | abe45@example.com | $242.00 |
processing | monserrat44@example.com | $837.00 |
success | silas22@example.com | $874.00 |
failed | carmella@example.com | $721.00 |
Filtering
Filter table data by column values using a controlled text input.
| Status | Amount | |
|---|---|---|
success | ken99@example.com | $316.00 |
success | abe45@example.com | $242.00 |
processing | monserrat44@example.com | $837.00 |
success | silas22@example.com | $874.00 |
failed | carmella@example.com | $721.00 |
pending | jessica@example.com | $456.00 |
success | michael@example.com | $623.00 |
processing | sarah@example.com | $198.00 |
Pagination
Navigate through pages of data with previous and next controls.
| Status | Amount | |
|---|---|---|
success | ken99@example.com | $316.00 |
success | abe45@example.com | $242.00 |
processing | monserrat44@example.com | $837.00 |
Row Selection
Select individual rows or all rows on the current page with checkboxes.
| Status | Amount | ||
|---|---|---|---|
success | ken99@example.com | $316.00 | |
success | abe45@example.com | $242.00 | |
processing | monserrat44@example.com | $837.00 | |
success | silas22@example.com | $874.00 | |
failed | carmella@example.com | $721.00 |
UX & Design Guidelines
Data Density & Readability
Use consistent padding within cells (px-4 py-2) and align numeric values to the right. Keep column count manageable (5-8 visible columns) and use column visibility toggles for optional fields. Alternate row styling with data-[state=selected]:bg-muted helps users track across wide tables.
Sorting & Filtering Patterns
Place filter inputs above the table, aligned with the column they control. Use variant="ghost" buttons in sortable column headers so they appear interactive without visual clutter. Show clear sort direction indicators (up/down arrows) so users always know the current sort state.
Responsive Behavior
Wrap the table in a horizontally scrollable container on small screens. Hide less-important columns by default on mobile using column visibility state. Consider switching to a stacked card layout below md breakpoint for complex tables. Pagination controls should remain accessible at all viewport sizes.
Empty & Loading States
Always provide a clear empty state message when no rows match the current filter (e.g., "No results found"). Use colSpan to span the full table width for the empty message. Show Skeleton rows during initial data loading to communicate layout structure.
Accessibility
Keyboard Navigation
- Tab -- Move focus between interactive elements (filters, sort buttons, checkboxes, pagination)
- Enter or Space -- Activate sort buttons, toggle checkboxes, or navigate pages
- Arrow Up / Arrow Down -- Navigate within dropdown menus (column visibility)
- Escape -- Close open dropdown menus or popovers
Screen Reader Support
- The native
<table>element provides implicit grid semantics for screen readers - Add
aria-labelto all selection checkboxes (e.g., "Select row", "Select all") - Use
aria-sort="ascending"or"descending"on sortable column headers - Announce filter results and page changes with
aria-live="polite"regions
Focus Management
Sort buttons and checkboxes display a visible focus ring using focus-visible:ring-[3px]. After toggling sort order, focus remains on the column header button. When navigating pages, focus should return to the first interactive element in the table or the pagination controls.
Row Selection Patterns
The "Select all" checkbox uses an indeterminate state when only some rows are selected. Each row checkbox includes a descriptive aria-label. Selected row count is displayed as live text so screen readers announce changes. Selection columns use enableSorting: false and enableHiding: false to keep them always visible and non-sortable.
ARIA Attributes
{/* Table with accessible caption */}
<Table>
<caption className="sr-only">Payment transactions</caption>
<TableHeader>...</TableHeader>
<TableBody>...</TableBody>
</Table>
{/* Row selection with labeled checkboxes */}
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label={`Select row ${row.index + 1}`}
/>
{/* Sortable header with aria-sort */}
<TableHead aria-sort={
column.getIsSorted() === "asc" ? "ascending"
: column.getIsSorted() === "desc" ? "descending"
: "none"
}>
<Button variant="ghost" onClick={() => column.toggleSorting()}>
Email <ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
</TableHead>
{/* Pagination with live region */}
<div aria-live="polite" className="text-sm text-muted-foreground">
Page {table.getState().pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
</div>Related Components
Table
A responsive static table for displaying simple tabular data without interactivity.
Pagination
Standalone pagination navigation with page numbers and next/previous links.
Card
An alternative layout for data display when visual richness is more important than density.
Checkbox
The selection control used for row selection and "select all" in data tables.
API Reference
The Data Table is a composition pattern built with @tanstack/react-table. The following are the primary options passed to useReactTable.
| Prop | Type | Default | Description |
|---|---|---|---|
| data | TData[] | — | Array of data objects to display as table rows. |
| columns | ColumnDef<TData>[] | — | Column definitions including accessors, headers, and cell renderers. |
| getCoreRowModel | () => CoreRowModel | — | Required. Returns the core row model for the table. |
| getSortedRowModel | () => SortedRowModel | undefined | Enables client-side sorting. Import from @tanstack/react-table. |
| getFilteredRowModel | () => FilteredRowModel | undefined | Enables client-side column filtering. Import from @tanstack/react-table. |
| getPaginationRowModel | () => PaginationRowModel | undefined | Enables client-side pagination. Import from @tanstack/react-table. |
| state | Partial<TableState> | {} | Controlled state object for sorting, filtering, pagination, row selection, and column visibility. |
| onSortingChange | OnChangeFn<SortingState> | undefined | Callback fired when the sorting state changes. |
| onColumnFiltersChange | OnChangeFn<ColumnFiltersState> | undefined | Callback fired when column filters change. |
| onRowSelectionChange | OnChangeFn<RowSelectionState> | undefined | Callback fired when row selection changes. |
ColumnDef Reference
Column definitions describe how each column accesses, renders, and behaves within the table.
| Prop | Type | Default | Description |
|---|---|---|---|
| accessorKey | string | — | Key to access the value from each data row object. |
| header | string | HeaderFunction | — | Column header content. Can be a string or render function for custom headers. |
| cell | CellFunction | auto | Cell render function with access to row data via row.getValue() and row.original. |
| enableSorting | boolean | true | Whether the column supports sorting when getSortedRowModel is enabled. |
| enableHiding | boolean | true | Whether the column can be toggled via column visibility controls. |
| id | string | accessorKey | Unique identifier for the column. Required for non-accessor columns like selection. |