DataTable
<DataTable> is the high-level list / table primitive. Pass data + columns and it handles header, body, sort, selection, row click, loading skeleton, and empty state. For raw control, use the lower-level Table.
When to use
- Every list / table screen with rows of typed data.
- The default for “I have a list and need to display it”.
Don’t use DataTable for: free-form layouts (Card + CardGrid), trees / hierarchies (use a tree primitive — TBD), or board-style pipelines (BoardView).
Default
| Stage | ||
|---|---|---|
| Acme Corp | Negotiation | $24,000 |
| Globex | Discovery | $8,500 |
| Initech | Closed-Won | $42,000 |
| Soylent | Discovery | $12,000 |
const columns: DataTableColumn<Row>[] = [ { id: 'name', header: 'Name', cell: (r) => r.name, sortable: true }, { id: 'stage', header: 'Stage', cell: (r) => r.stage }, { id: 'amount', header: 'Amount', cell: (r) => r.amount, numeric: true, sortable: true },];
<DataTable<Row> data={rows} columns={columns} sortColumn={sortColumn} sortDirection={sortDirection} onSortChange={(col, dir) => setSort({ col, dir })}/>API
| Prop | Type | Default | Description |
|---|---|---|---|
data * | T[] | — | Row data. |
columns * | DataTableColumn<T>[] | — | Column descriptors — { id, header, cell, sortable?, numeric?, className?, cellClassName? }. |
rowId | (row: T) => string | — | Stable row id. Defaults to (row as any).id. Required for selection. |
sortColumn | string | null | — | Controlled active sort column. |
sortDirection | SortDirection | — | "asc" | "desc" | null. Pair with sortColumn. |
onSortChange | (column, direction) => void | — | Fires on header click. Caller cycles state. |
selectedIds | Set<string> | — | Controlled selection. Renders the leading checkbox column when set. |
onSelectionChange | (ids: Set<string>) => void | — | Fires on row checkbox / select-all toggle. |
onRowClick | (row: T) => void | — | Whole-row click. Stops propagation in interactive cells. |
rowActions | (row: T) => ReactNode | — | Trailing actions cell — right-aligned, click stops propagation. |
isLoading | boolean | false | Show skeleton rows during initial load. |
loadingRowCount | number | 5 | How many skeleton rows. |
isFiltered | boolean | false | Picks the right empty-state variant. |
emptyState | ReactNode | — | Shown when data is empty and !isFiltered. |
filteredEmptyState | ReactNode | — | Shown when data is empty and isFiltered. |
Design guidelines
✓ Do
- Make every column with sortable data sortable. Users sort more than they expect to.
- Set isFiltered + filteredEmptyState so "no results" reads correctly.
- Use rowActions for per-row actions; lift bulk actions to a toolbar above the table.
✗ Don't
- Render >7 columns by default — beyond that the table becomes a horizontal scroller.
- Use DataTable for kanban / pipeline data. BoardView is correct for stage-driven flows.
- Hand-roll sort state. Pass controlled sortColumn + sortDirection.
Accessibility
- Composes
Tableunder the hood — semantic<table>/<thead>/<tbody>/<tr>/<td>. - Sortable headers compose
SortableTableHeadwitharia-sort. - Selection uses real
<input type="checkbox">with associated label.
Related
Table— Lower-level primitive.SortableTableHead— Sortable column header used internally.TablePagination— Pair with for paginated lists.DataGroup— Multi-DataTable grouping.