Table
A structural, stateless table primitive built on native HTML table semantics with composable parts for header, body, footer, rows, cells, and captions.
Features
- Native table semantics
- Composable parts
- Row and column headers
- Stateless
- Forwards refs and native props
- Horizontal overflow support
Installation
npm install @ariaui/table
Examples
Composable table parts—Header, Body, Row, Cell, Footer, and Caption—over native <table> semantics.
The first playground is a static invoice listing with badges. The second is an interactive data table (filter input, column menu, selection, row actions) with a matching exampleSource fence; shared layout classes live in tableExampleTokens.ts.
Invoice table
Header, body, footer, and caption with status badges.
No preview output yet.
Data table
Filtering, column visibility, row selection, status badges, and row actions.
No preview output yet.
Anatomy
import * as Table from "@ariaui/table";
export default function Example() {
return (
<Table.Root>
<Table.Caption />
<Table.Header>
<Table.Row>
<Table.ColumnHeader />
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.RowHeader />
<Table.Cell />
</Table.Row>
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.Cell />
</Table.Row>
</Table.Footer>
</Table.Root>
);
}
API Reference
Root
Wraps the table in an overflow container for horizontal scrolling. The ref is forwarded to the inner `<table>` element.
Header
Renders a `<thead>` element.
Body
Renders a `<tbody>` element.
Row
Renders a `<tr>` element.
Cell
Renders a `<td>` element.
ColumnHeader
Renders a `<th>` element for column header semantics. Pass `scope="col"` explicitly when you need to be strict about the association.
RowHeader
Renders a `<th>` with `scope="row"` by default so the cell names its row for assistive tech.
| Prop | Type | Default |
|---|---|---|
scope | string | 'row' |
Caption
Renders a `<caption>` element that provides an accessible name for the table.
Accessibility
Table is built on native HTML table semantics, which assistive tech already understands:
Rootrenders a<table>, so screen readers announce row and column counts and support built-in table navigation (in NVDA/JAWS, Ctrl+Alt+Arrow keys move between cells).- Provide a
Caption— or pair the table with anaria-labelledby/aria-label— so the table has a human-readable name. - Use
ColumnHeaderfor column<th>cells andRowHeaderfor row-identifying<th>cells.RowHeaderdefaults toscope="row"; addscope="col"onColumnHeaderwhen you need to be explicit. - Do not remove default roles with
role="presentation"or wrap cells in non-semantic elements — the native markup is what makes the table accessible. - For sortable columns add
aria-sorton the relevantColumnHeader; for selectable rows usearia-selectedonRowand manage focus yourself — Table is intentionally stateless. - When the table scrolls horizontally inside
Root, make the scroll container focusable (tabIndex={0}) and give it a label so keyboard-only users can scroll it.