DisplayReact
A native table of rows and columns that can sort, select rows and, in grid mode, move focus from cell to cell.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<DataTable.Root>
<DataTable.Caption />
<DataTable.Header>
<DataTable.Row>
<DataTable.ColumnHeader>
<DataTable.SortTrigger>
<DataTable.SortIndicator />
</DataTable.SortTrigger>
</DataTable.ColumnHeader>
</DataTable.Row>
</DataTable.Header>
<DataTable.Body>
<DataTable.RowHeader />
<DataTable.Cell />
</DataTable.Body>
</DataTable.Root>
// Not in this example: DataTable.CheckboxIndicator, DataTable.Empty, DataTable.Footer, DataTable.RowCheckbox, DataTable.SelectAllCheckboxExamples
Selection
selectable and multiple, a RowCheckbox per row and a SelectAllCheckbox; Alan Turing is disabled, and the selected values are listed below.
Grid
grid: tasks with an owner button and Edit and Delete in their cells; Enter on a row header runs the row's onAction, and Empty shows when all are deleted.
Pagination
23 invoices, five a page, with Pagination below; the app slices its rows by the page and the tab stop moves to the new page's first row.
Virtualized
1,000 orders as rows, virtualized, with fewer than 30 rows mounted; Control+End and the page keys reach rows that are not mounted.
API reference
40 props across 15 parts, in React syntax. className, style, render are listed once, under Shared props.
BodyDataTable.Body
The body row group: the data rows, and DataTable.Empty while there are none. Renders a <tbody>.
CaptionDataTable.Caption
The title of the table: it names the table unless aria-label or aria-labelledby is passed to the root. Place it as the first child of DataTable.Root. Renders a <caption>.
CellDataTable.Cell
A data cell of a row; a gridcell in grid mode. Renders a <td>.
| Prop | Type | Default |
|---|---|---|
columnIndexThe 0-based position of the cell's column among all columns, rendered or not. | number | — |
| Data attribute | Description |
|---|---|
data-selected | Present when the cell's row is selected. |
data-disabled | Present when the cell's row is disabled. |
data-highlighted | Present in grid mode when focus is on the cell or inside it. |
CheckboxIndicatorDataTable.CheckboxIndicator
Shows the tick of a DataTable.RowCheckbox or DataTable.SelectAllCheckbox, rendered while it is checked or mixed. Renders a <span>.
| Prop | Type | Default |
|---|---|---|
keepMountedWhether to keep the element in the DOM when the checkbox is not checked. | boolean | false |
ColumnHeaderDataTable.ColumnHeader
The header of a column. It carries aria-sort while the root's sort is on its column, whatever set the sort. Renders a <th>.
| Prop | Type | Default |
|---|---|---|
columnThe column's key: the header carries aria-sort while the root's sort.column equals it, | string | — |
labelThe column's name in the sort announcement. | string | — |
columnIndexThe 0-based position of the column among all columns, rendered or not. | number | — |
| Data attribute | Description |
|---|---|
data-sortable | Present when the header holds a DataTable.SortTrigger. |
data-sort-direction | The direction of the column's sort, while it is sorted. |
data-highlighted | Present in grid mode when focus is on the header or inside it. |
EmptyDataTable.Empty
The row shown while the body has no rows; put a DataTable.Cell with colSpan inside. It is not a grid row: arrows skip it, and its controls are reached by Tab. Renders nothing otherwise. Place it inside DataTable.Body. Renders a <tr>.
FooterDataTable.Footer
The footer row group: summary rows. Renders a <tfoot>.
HeaderDataTable.Header
The header row group: the rows of column headers. Renders a <thead>.
RootDataTable.Root
Groups all parts of the data table: a native table, or with grid an interactive grid with cell focus., followed by the status region. Renders a <table>.
| Prop | Type | Default |
|---|---|---|
gridWhether the table is an interactive grid: role="grid", cell focus, the grid keys and one | boolean | false |
sortThe current sort: a column and its direction, or null. | DataTableSort | — |
defaultSortThe uncontrolled sort when the table is initially rendered. | DataTableSort | — |
onSortChangeEvent handler called when a DataTable.SortTrigger is pressed. | ((sort: DataTableSort, eventDetails: { reason: "trigger-press"; event: MouseEvent | PointerEvent | KeyboardEvent | TouchEvent; cancel: () => void; allowPropagation: () => void; isCanceled: boolean; isPropagationAllowed: boolean; trigger: Element | undefined; }) => void) | — |
allowUnsortedWhether the sort cycle returns to unsorted after the second direction. | boolean | true |
valueThe selected rows. | DataTableInputValue<Value, Multiple> | null | — |
defaultValueThe uncontrolled selected rows when the table is initially rendered. | DataTableInputValue<Value, Multiple> | null | — |
onValueChangeEvent handler called when the selection changes, once per gesture. | ((value: DataTableOutputValue<Value, Multiple>, eventDetails: DataTableRootChangeEventDetails) => void) | — |
selectableWhether rows can be selected at all. | boolean | false |
multipleWhether several rows can be selected. | Multiple | false |
disallowEmptySelectionWhether the gesture that would clear the last selected row is refused. | boolean | false |
selectOnPressWhether a press on a selectable row outside its controls selects it. | boolean | false |
isRowEqualToValueCustom comparison logic used to determine if a row value matches a selected value. | ((row: Value, value: Value) => boolean) | — |
disabledWhether the component should ignore user interaction. | boolean | false |
rowsEvery body row's value in order, rendered or not: for virtualized, and for select-all and | readonly Value[] | — |
virtualizedWhether the app renders only some body rows (a virtualizer), each with its index. | boolean | false |
isRowDisabledWhether a value of rows is disabled, for rows that are not rendered. | ((row: Value) => boolean) | — |
onRowHighlightedVirtualized grid only: called when a key targets a row that is not rendered. | ((row: Value, eventDetails: DataTableHighlightDetails) => void) | — |
columnCountThe number of columns the table has, rendered or not. | number | — |
labelsThe texts of the status region and the checkboxes. | Partial<DataTableLabels> | — |
| Data attribute | Description |
|---|---|
data-grid | Present in grid mode. |
data-selectable | Present when rows can be selected. |
data-multiple | Present when several rows can be selected. |
data-disabled | Present when the table is disabled. |
data-empty | Present when the body has no rows. |
data-sorted | Present when a sort is set. |
RowDataTable.Row
A row of the table, in its header, body or footer. Renders a <tr>.
| Prop | Type | Default |
|---|---|---|
children | React.ReactNode | — |
valueA unique value that identifies this row. | any | — |
labelThe row's name in the announcements, when it has no DataTable.RowHeader. | string | — |
disabledWhether the component should ignore user interaction. | boolean | false |
selectableWhether the row can be selected, in a table that is selectable. | boolean | true |
onActionGrid mode only: called when the row is activated (Enter on a cell without controls, or a | ((eventDetails: DataTableActionDetails) => void) | — |
indexVirtualized only: the position of the row in rows. | number | — |
| Data attribute | Description |
|---|---|
data-selected | Present when the row is selected. |
data-disabled | Present when the row is disabled. |
data-highlighted | Present in grid mode when focus is in one of the row's cells. |
RowCheckboxDataTable.RowCheckbox
The checkbox that selects its row. Named "Select" plus the row's DataTable.RowHeader. A press or Space toggles the row; with Shift it selects the range from the last toggled row. Renders a <span>.
| Prop | Type | Default |
|---|---|---|
disabledWhether the component should ignore user interaction. | boolean | false |
nativeButtonWhether the component renders a native <button> element when replacing it | boolean | false |
RowHeaderDataTable.RowHeader
The cell that names its row: the row's checkbox, its grid row and the announcements read it. Renders a <th>.
| Prop | Type | Default |
|---|---|---|
columnIndexThe 0-based position of the cell's column among all columns, rendered or not. | number | — |
SelectAllCheckboxDataTable.SelectAllCheckbox
The checkbox that selects every row, or clears them when all are selected; mixed while some are. Disabled rows keep their state. Needs a multiple table. Renders a <span>.
| Prop | Type | Default |
|---|---|---|
disabledWhether the component should ignore user interaction. | boolean | false |
nativeButtonWhether the component renders a native <button> element when replacing it | boolean | false |
SortIndicatorDataTable.SortIndicator
Shows the direction of its column's sort; hidden from assistive technology, which reads aria-sort. Always rendered. Place it inside a DataTable.ColumnHeader. Renders a <span>.
SortTriggerDataTable.SortTrigger
The button that sorts its column. Its content is its name. Place it inside a DataTable.ColumnHeader that has a column. Renders a <button>.
| Prop | Type | Default |
|---|---|---|
firstDirectionThe direction a press sorts an unsorted column in. | DataTableSortDirection | 'ascending' |
disabledWhether the component should ignore user interaction. | boolean | false |
nativeButtonWhether the component renders a native <button> element when replacing it | boolean | true |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| EnterSpace | Sorts by the column: its first direction, then the other, then none | SortTrigger |
| Space | In table mode, toggles the focused row checkbox | RowCheckbox |
| ShiftSpace | On a row checkbox, selects the range from the anchor | RowCheckbox |
| Tab | In grid mode, enters the table on its one tab stop | Root |
| ArrowRightArrowLeft | In grid mode, moves to the next or previous cell and stops at the edges | Root |
| ArrowDownArrowUp | Moves to the cell below or above in the same column, header and footer included | Root |
| HomeEnd | Moves to the first or last cell of the row | Root |
| ControlHomeControlEnd | Moves to the first or last cell of the table, mounted or not | Root |
| PageDownPageUp | Moves ten rows in the same column and stops at the ends | Root |
| EnterF2 | On a cell with several controls, moves to its first one; F2 returns | Cell |
| Escape | From a control, returns to its cell | Cell |
| Enter | On a cell without controls, runs the row's onAction | Row |
| Space | In grid mode, toggles the focused row | Row |
| ShiftArrowDownShiftArrowUp | With multiple, extends the selection from the anchor | Root |
| ControlAMetaA | With multiple in grid mode, selects every enabled row, or clears them when all are selected | Root |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Root | the native table, role="grid" with grid, aria-multiselectable with multiple in grid mode, aria-rowcount when virtualized | a table is read as a table, and a grid as one widget; a development build warns without a name |
| Caption | the native caption, which names the table; an aria-label on Root wins over it | the table is announced by its name when a reader enters it |
| ColumnHeader | columnheader, aria-sort on the sorted header only, never "none" | the sort is read from the header, not from the indicator |
| RowHeader | rowheader; in grid mode it names its row (aria-labelledby) | moving down a column reads which row each cell belongs to |
| Row | aria-selected on selectable rows and aria-disabled on disabled ones in grid mode only; aria-rowindex when virtualized | a table-mode row says nothing it cannot act on; the checkbox carries the state there |
| RowCheckbox | role="checkbox", named "Select" plus its row header; aria-disabled on a disabled row | ten checkboxes are not all read as "Select" |
| SelectAllCheckbox | role="checkbox", named "Select all", aria-checked="mixed" while some rows are selected | the header checkbox tells whether the page is all, some or none selected |
| SortIndicator | aria-hidden | the arrow is for sight; aria-sort says it |
| Root | one polite role="status" region next to the table, always mounted | sorts, ranges and select-all are announced, since readers do not announce aria-sort or aria-selected changes |
Focus order
- In table mode the table is not a stop: Tab walks its sort buttons, checkboxes, links and buttons in reading order.
- In grid mode the table is one Tab stop. Inside, the arrow keys,
Home,End,Control+Home,Control+Endand the page keys move between cells; a cell whose only control is a button, link or checkbox focuses that control. - A cell with several controls is entered with
EnterorF2;Tabwalks its controls and then leaves the table, andEscapeorF2returns to the cell.