Table
A headless interactive table primitive with grid-style keyboard navigation, row selection, explicit sortable header triggers, and a composable part-based API.
| Service | Owner | Status |
|---|---|---|
| Checkout API | Infra | Healthy |
| Identity Worker | Platform | Rolling |
| Billing Queue | Finance | Healthy |
| Session Cache | Platform | Degraded |
| Audit Trail | Security | Rolling |
| Total | 5 services |
Anatomy
Table.Root renders an interactive grid over native table markup. Wrap each header cell in a Table.Column — a metadata-only part that registers the column — and opt into sorting or resizing per column by composing Table.SortTrigger or Table.ColumnResizer inside its Table.ColumnHeaderCell.
<script>
import { Table } from '@human-kit/ui';
</script>
<Table.Root aria-label="Users table">
<Table.Header>
<Table.Row>
<Table.Column id="email" rowHeader>
<Table.ColumnHeaderCell>Email</Table.ColumnHeaderCell>
</Table.Column>
<Table.Column id="group">
<Table.ColumnHeaderCell>Group</Table.ColumnHeaderCell>
</Table.Column>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row id="danilo">
<Table.Cell>danilo@example.com</Table.Cell>
<Table.Cell>Developer</Table.Cell>
</Table.Row>
<Table.EmptyState>No users found.</Table.EmptyState>
</Table.Body>
</Table.Root>Row selection
Set selectionMode="multiple" (or "single") and give every body row an id. Table.Checkbox and Table.CheckboxIndicator compose explicit selection UI inside cells — the header checkbox selects all rows and shows an indeterminate state, while disabledKeys keeps specific rows rendered but non-selectable.
| Group | ||
|---|---|---|
| danilo@example.com | Developer | |
| zahra@example.com | Admin | |
| jasper@example.com | Developer | |
| marta@example.com | Support | |
| nora@example.com | Finance |
Pagination
Pagination stays consumer-owned: slice the dataset before rendering and drive the current page from external controls or app state.
Usage guidelines
- Use
Table.Rootas the stateful container for focus, selection, and sorting state, and give itaria-labeloraria-labelledby. - Wrap each header cell in
Table.Columnso the table can register stable column metadata;Table.Columnrenders no DOM by itself. - Use
selectedKeys/onSelectionChangefor controlled row selection anddefaultSelectedKeysfor uncontrolled initial selection. - Use
selectionBehavior="toggle"to allow deselecting an already selected row, or"replace"to keep selected rows selected when pressed again. - Use
sortDescriptor/onSortChangefor controlled sorting anddefaultSortDescriptorfor uncontrolled initial sort state;Table.SortTriggerinside a header cell makes the owning column sortable. - Use
columnWidths/onColumnWidthsChangefor controlled column widths (px,%, orfr), and addTable.ColumnResizerinsideTable.ColumnHeaderCellto make a column resizable. - Dedicated utility columns like selection checkboxes should usually set an explicit
width,minWidth, andmaxWidthonTable.Columnso sibling resizes do not redistribute their space. - Use
Table.EmptyStateinsideTable.Bodyinstead of conditionally rendering freeform body content. - Use
Table.InteractiveCellfor body cells that contain their own focusable controls.
Accessibility
Table.Rootrenders an interactivegridover native table markup, and keyboard navigation uses rovingtabindexacross header and body cells.- Body rows can also become the active focus target when horizontal navigation moves past the start or end of a row, and repeated left/right navigation loops back into the opposite edge cell.
- First-column body cells become
rowheaderwhen their associated column hasrowHeader. - Disabled rows remain rendered and non-selectable, but are skipped by focus navigation.
Table.SortTriggerrenders the trigger button, while the header cell remains the roving-focus target; sort changes are mirrored into a polite live region for screen readers.- Column resize handles are keyboard accessible separators: press
Enterto enter resize mode, use the horizontal arrow keys to resize,Hometo jump to the minimum width,Endto auto-fit, andEnteragain to exit.
API reference
Root
The stateful table container. Renders an interactive grid over native table markup and manages focus, selection, sorting, column widths, and column visibility.
* required. Native HTML attributes of the underlying element are also accepted.
Column
Metadata-only wrapper for a column. Renders no DOM itself; it registers the column and should wrap a single Table.ColumnHeaderCell.
* required. Native HTML attributes of the underlying element are also accepted.
Header
The table head section containing the header row.
* required. Native HTML attributes of the underlying element are also accepted.
Body
The table body section. Renders the data rows and hosts the empty state.
* required. Native HTML attributes of the underlying element are also accepted.
EmptyState
A placeholder row shown inside the body while the table has no rows. Use it instead of conditionally rendering freeform body content.
* required. Native HTML attributes of the underlying element are also accepted.
Footer
The table foot section, for summary rows.
* required. Native HTML attributes of the underlying element are also accepted.
Row
A table row. Body rows take an id to participate in selection, focus navigation, and row actions.
* required. Native HTML attributes of the underlying element are also accepted.
ColumnHeaderCell
A header cell. Remains the roving-focus target for its column even when it contains a sort trigger or resizer.
* required. Native HTML attributes of the underlying element are also accepted.
SortTrigger
The explicit opt-in button for sorting. Rendering it inside a header cell makes the owning column sortable and toggles the root's sortDescriptor.
* required. Native HTML attributes of the underlying element are also accepted.
ColumnResizer
A keyboard-accessible resize handle. Rendering it inside a header cell makes the owning column resizable.
* required. Native HTML attributes of the underlying element are also accepted.
Checkbox
An explicit selection control inside header or body cells. Auto-hides in header cells unless selectionMode is 'multiple', and everywhere when selection is disabled.
* required. Native HTML attributes of the underlying element are also accepted.
CheckboxIndicator
The visual mark inside a table checkbox, composing custom affordances for checked and indeterminate states.
* required. Native HTML attributes of the underlying element are also accepted.
Cell
A body or footer cell participating in grid keyboard navigation. First-column body cells render as rowheader when their column has rowHeader.
* required. Native HTML attributes of the underlying element are also accepted.
InteractiveCell
A body cell for content with its own focusable controls. The cell keeps grid keyboard navigation while focus is on it; focused descendants own their interactions.
* required. Native HTML attributes of the underlying element are also accepted.
More advanced patterns — column visibility, fixed and pinned columns, sticky headers, column resizing, and row actions — are supported by the same parts; see the API reference above for the corresponding props.