Table

A headless interactive table primitive with grid-style keyboard navigation, row selection, explicit sortable header triggers, and a composable part-based API.

ServiceOwnerStatus
Checkout API Infra Healthy
Identity Worker Platform Rolling
Billing Queue Finance Healthy
Session Cache Platform Degraded
Audit Trail Security Rolling
Total 5 services
Selection unavailable for this row.

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.

Email Group
danilo@example.com Developer
zahra@example.com Admin
jasper@example.com Developer
marta@example.com Support
nora@example.com Finance
Selection unavailable for this row.

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.Root as the stateful container for focus, selection, and sorting state, and give it aria-label or aria-labelledby.
  • Wrap each header cell in Table.Column so the table can register stable column metadata; Table.Column renders no DOM by itself.
  • Use selectedKeys / onSelectionChange for controlled row selection and defaultSelectedKeys for 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 / onSortChange for controlled sorting and defaultSortDescriptor for uncontrolled initial sort state; Table.SortTrigger inside a header cell makes the owning column sortable.
  • Use columnWidths / onColumnWidthsChange for controlled column widths (px, %, or fr), and add Table.ColumnResizer inside Table.ColumnHeaderCell to make a column resizable.
  • Dedicated utility columns like selection checkboxes should usually set an explicit width, minWidth, and maxWidth on Table.Column so sibling resizes do not redistribute their space.
  • Use Table.EmptyState inside Table.Body instead of conditionally rendering freeform body content.
  • Use Table.InteractiveCell for body cells that contain their own focusable controls.

Accessibility

  • Table.Root renders an interactive grid over native table markup, and keyboard navigation uses roving tabindex across 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 rowheader when their associated column has rowHeader.
  • Disabled rows remain rendered and non-selectable, but are skipped by focus navigation.
  • Table.SortTrigger renders 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 Enter to enter resize mode, use the horizontal arrow keys to resize, Home to jump to the minimum width, End to auto-fit, and Enter again 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.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-disabled-behavior The configured disabled behavior ('all' | 'selection').
data-focus-visible Present while focus inside the table should be visibly indicated (keyboard modality).
data-focus-within Present while focus is inside the table.
data-selection-behavior The configured selection behavior ('toggle' | 'replace').
data-selection-mode The configured selection mode ('none' | 'single' | 'multiple').
data-table-column-resizer Marks resize handles inside the table; the root switches to a fixed table layout when any are present.
data-table-implicit-width Present on a column's col element while it still uses an implicit width (before widths are materialized by a resize).

Column

Metadata-only wrapper for a column. Renders no DOM itself; it registers the column and should wrap a single Table.ColumnHeaderCell.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Header

The table head section containing the header row.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-table-header Identifies the header element.

Body

The table body section. Renders the data rows and hosts the empty state.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-empty Present while the body has no rows.
data-table-body Identifies the body element.
data-virtual-spacer Identifies the top or bottom spacer rows used by virtualization ('top' | 'bottom').

EmptyState

A placeholder row shown inside the body while the table has no rows. Use it instead of conditionally rendering freeform body content.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-empty Identifies the empty state row.

The table foot section, for summary rows.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-table-footer Identifies the footer element.

Row

A table row. Body rows take an id to participate in selection, focus navigation, and row actions.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-actionable Present when activating the row triggers a row action.
data-disabled Present when the row is disabled.
data-focus-visible Present while the row itself is focused and focus should be visibly indicated.
data-focus-visible-within Present while an element inside the row has visibly indicated focus.
data-focus-within Present while focus is inside the row.
data-focused Present while the row itself has focus.
data-selected Present while the row is selected.
data-selection-disabled Present when the row cannot be selected.

ColumnHeaderCell

A header cell. Remains the roving-focus target for its column even when it contains a sort trigger or resizer.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-column-index Index of the cell's column among visible columns.
data-focus-visible Present while the cell is focused and focus should be visibly indicated.
data-focus-visible-within Present while an element inside the cell has visibly indicated focus.
data-focus-within Present while focus is inside the cell.
data-focused Present while the cell has focus.
data-pin-edge The edge the owning column is pinned to ('left' | 'right').
data-pinned Present when the owning column is pinned.
data-sort-direction The active sort direction while this column is sorted ('ascending' | 'descending').
data-sortable Present when the owning column is sortable.

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.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-sort-direction The active sort direction while the owning column is sorted ('ascending' | 'descending').
data-sorted Present while the owning column is the active sort column.
data-table-sort-trigger Identifies the sort trigger element.

ColumnResizer

A keyboard-accessible resize handle. Rendering it inside a header cell makes the owning column resizable.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-focus-visible Present while the handle is focused and focus should be visibly indicated.
data-focused Present while the handle has focus.
data-resizable Present when the owning column can currently be resized.
data-resizable-direction The direction the handle resizes toward (currently always 'right').
data-resizing Present while a pointer or keyboard resize is in progress.
data-table-column-resizer Identifies the resize handle element.
data-testid Identifies the hidden resize status live region ('column-resize-status'); not a styling target.

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.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-table-checkbox Identifies the checkbox element.

CheckboxIndicator

The visual mark inside a table checkbox, composing custom affordances for checked and indeterminate states.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-checkbox-indicator Identifies the indicator element.
data-checked Present while the checkbox is checked.
data-disabled Present when the checkbox is disabled.
data-focus-visible Present while focus should be visibly indicated (keyboard modality).
data-focused Present while the checkbox has focus.
data-indeterminate Present while the checkbox is indeterminate (partial selection).
data-pressed Present while the checkbox is actively pressed.
data-unchecked Present while the checkbox is unchecked (with `forceMount`).

Cell

A body or footer cell participating in grid keyboard navigation. First-column body cells render as rowheader when their column has rowHeader.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-actionable Present when activating the cell's row triggers a row action.
data-column-index Index of the cell's column among visible columns.
data-disabled Present when the cell's row is disabled.
data-focus-visible Present while the cell is focused and focus should be visibly indicated.
data-focused Present while the cell has focus.
data-pin-edge The edge the owning column is pinned to ('left' | 'right').
data-pinned Present when the owning column is pinned.
data-row-selected Present while the cell's row is selected.
data-selection-disabled Present when the cell's row cannot be selected.

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.

Prop Type Default

* required. Native HTML attributes of the underlying element are also accepted.

Data attribute Description
data-actionable Present when activating the cell's row triggers a row action.
data-column-index Index of the cell's column among visible columns.
data-disabled Present when the cell's row is disabled.
data-focus-visible Present while the cell is focused and focus should be visibly indicated.
data-focused Present while the cell has focus.
data-pin-edge The edge the owning column is pinned to ('left' | 'right').
data-pinned Present when the owning column is pinned.
data-row-selected Present while the cell's row is selected.
data-selection-disabled Present when the cell's row cannot be selected.

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.