TrademarkTrademark
Docs
Ctrl k
Search docs...
Components

DataTable

Updated: October 11, 2026
View on GitHub
Soon
Not released yet. This is on main and is not in any published version yet. It will not install today.

DataTable renders an array of your own rows through a list of column definitions. Where Table takes cells that are already rendered, DataTable keeps the rows as data, so it can sort by the values rather than by the text on screen, select rows by id, and page through them. It draws the same table as Table.

DataTable is generic over the row type, so cell and sort receive your rows typed. A column without cell shows row[key]. Name the table with aria-label, or point aria-labelledby at a heading above it.

Sorting

A sortable column's header is a button. Each press cycles ascending, descending and back to the rows' own order, and the sorted header carries aria-sort. Without a sort function the column compares row[key]: numbers as numbers, dates by time, text in natural order ("Item 2" before "Item 10"), with empty values last in both directions. Give the column a sort comparator, written ascending, when the key is not a field of the row or its values need their own order:

DataTable keeps the sort itself, starting from defaultSort, or follows sort and onSortChange when the host owns it. null is unsorted. A new sort returns to the first page.

Selection and pagination

selectable adds a checkbox column. The header checkbox selects or clears the rows on screen, and shows a mixed state when only some of them are selected; selection is kept across pages. getRowId gives each row the id that selection reports; without it a row's id field is used, or its index. getRowLabel names each row's checkbox for screen readers.

paginated shows the rows a page at a time with Pagination below; perPageOptions adds a page-size select.

Server-side data

When the server sorts and pages, pass the current page's rows with count, the number of rows on the server (or total, the number of pages). DataTable then neither sorts nor slices the rows: it reports onPageChange, onPerPageChange and onSortChange, and shows loading while you fetch. Give rows a getRowId here, since an index repeats from page to page.

Empty and loading

With no rows DataTable shows an empty state; pass your own as emptyState. While loading, skeleton rows stand in for the page (as many as perPage), the table is marked aria-busy, and sorting, selection and pagination are disabled.

stickyHeader keeps the header row in view while the rows scroll; pair it with maxHeight, which on DataTable caps the scroll area. striped, hoverable and compact work as on Table.

API reference

Type
Default
columnsrequired
The columns, in order. See DataTableColumn below.
DataTableColumn<T>[]—
rowsrequired
Your rows: every row, or with count or total only the current page.
T[]—
getRowId
A stable id per row, which selection reports. Defaults to row.id, then the index.
(row: T, index: number) => string—
sort
The sorted column and direction when the host owns it; null for unsorted.
DataTableSortnull
—
defaultSort
The sort to start with.
DataTableSortnull
null
onSortChange
Called with the new sort, or null.
(sort: DataTableSort | null) => void—
selectable
Add a checkbox column with select-all.
booleanfalse
selected
The selected rows' ids when the host owns them.
string[]—
defaultSelected
The ids selected to start with.
string[]—
onSelectionChange
Called with every selected id after each change.
(selected: string[]) => void—
getRowLabel
The accessible name of a row's checkbox.
(row: T) => string—
paginated
Show the rows a page at a time.
booleanfalse
page
The current page, from 1, when the host owns it.
number—
defaultPage
The page to start on.
number1
onPageChange
Called with the new page.
(page: number) => void—
perPage
Rows per page when the host owns it.
number—
defaultPerPage
Rows per page to start with.
number10
perPageOptions
Page sizes to offer in a select.
number[]—
onPerPageChange
Called with the new page size.
(perPage: number) => void—
count
Rows on the server. The rows are then one page, sorted and sliced by the host.
number—
total
Pages on the server, as count.
number—
loading
Show skeleton rows and disable the controls.
booleanfalse
emptyState
What to show when there are no rows.
ReactNode—
stickyHeader
Keep the header row in view while the rows scroll.
booleanfalse
striped
Alternate row backgrounds.
booleanfalse
hoverable
Highlight the row under the pointer.
booleantrue
compact
Tighter rows.
booleanfalse
labels
The checkbox, pagination and per-page names, to translate them.
Partial<DataTableLabels>—
aria-label
The table's accessible name.
string—
aria-labelledby
The id of the element that names the table.
string—
…and every FlexProps propinherited—

DataTableColumn

Type
Default
keyrequired
The column's id, the key a sort reports, and the field shown when there is no cell.
string—
headerrequired
The header cell's content.
React.ReactNode—
cell
Renders the cell. Without it the cell shows row[key].
(row: T, index: number) => React.ReactNode—
sortable
Let the reader sort by this column.
booleanfalse
sort
Ascending comparator. Without it rows compare by row[key].
(a: T, b: T) => number—
align
Aligns the header and the cells.
leftcenterright
left
width
A CSS width for the column.
string—

DataTableLabels

Type
Default
selectAll
The select-all checkbox's name; "Select all rows on this page" when paginated.
string"Select all rows"
selectRow
Each row checkbox's name, unless getRowLabel names it.
string"Select row"
pagination
The pagination landmark's name.
string"Pagination"
perPage
The per-page select's label.
string"Rows per page"
previous, next, first, last
As on Pagination.
string—
Edit this page on GitHub
TrademarkTrademark
Built with curiosity by Lorant One and the Design Engineers Club