DataTable
Records as a table: a caption, column headers, a row for each record and, when asked, a way to sort and a link to each record’s page.
import { DataTable } from '@zitdevs/ui';Examples
Section titled “Examples”Sorted by link. Each sortable header links to the order that follows its own, and the first cell of a row links to its page:
| Project | Owner | Status | Hours |
|---|---|---|---|
| Customer portal | Ada | 128 | |
| Billing migration | Grace | 342 | |
| Design system | Linus | 96 |
<DataTable id="projects" caption="Projects" columns={[ { id: 'name', header: 'Project', cell: (row) => row.name, sortable: true, rowHeader: true }, { id: 'owner', header: 'Owner', cell: (row) => row.owner, sortable: true }, { id: 'hours', header: 'Hours', cell: (row) => row.hours, align: 'end' }, ]} rows={projects} rowKey={(row) => row.id} sort={{ column: 'name', direction: 'ascending' }} sortHref={(column, direction) => `/projects?sort=${column}:${direction}`} rowHref={(row) => `/projects/${row.id}`}/>Sorted by buttons, dense, with the caption left to assistive technology. The headers are submit
buttons of a GET form, so Enter and Space press them:
| Status | Hours | ||
|---|---|---|---|
| Customer portal | Ada | 128 | |
| Billing migration | Grace | 342 | |
| Design system | Linus | 96 |
<DataTable {...table} density="compact" captionHidden sort={{ column: 'owner', direction: 'descending' }} sortAction="/projects" sortFields={{ team: 'platform' }}/>Empty, and loading:
| Project | Owner | Status | Hours |
|---|---|---|---|
No closed projectsProjects show up here once their last delivery is approved. | |||
| Project | Owner | Status | Hours |
|---|---|---|---|
| Loading | |||
<DataTable {...table} rows={[]} empty={{ title: 'No closed projects' }} /><DataTable {...table} loadingRows={3} />| Prop | Type | Default | Notes |
|---|---|---|---|
id |
string |
required | Keys the caption, and the sort form (<id>-sort). |
caption |
string |
required | Says what the table lists. It names the table and its scroll region. |
captionHidden |
boolean |
false |
Keeps the caption for assistive technology when a heading above says the same. |
columns |
readonly DataTableColumn<Row>[] |
required | { id, header, cell, sortable?, align?, rowHeader?, hideHeader? }. |
rows |
readonly Row[] |
required | Already in the order to show. |
rowKey |
(row) => string |
required | A stable key, such as the record’s id. |
sort |
{ column; direction } |
— | The order the rows arrived in: sets aria-sort on that header. |
sortHref |
(column, direction) => string |
— | Sorts by link. The direction is the one that follows the current order. |
sortAction |
string |
— | Sorts by button instead: a GET form to this address. Ignored when sortHref is set. |
sortName |
string |
'sort' |
The parameter a sort button sends, valued <column>:<direction>. |
sortFields |
Record<string, string> |
— | Hidden fields of the sort form, such as the filters in force. |
rowHref |
(row) => string | undefined |
— | Links the row’s first cell to its page. A record with none is not linked. |
linkAs |
LinkComponent |
'a' |
Renders the links, such as Next’s Link. |
density |
'comfortable' | 'compact' |
'comfortable' |
Cell padding. |
empty |
EmptyStateProps |
— | Shown, spanning the columns, when there are no rows. |
loadingRows |
number |
— | Shows this many skeleton rows in place of the records, and marks the table aria-busy. |
labels |
Partial<DataTableLabels> |
English | { loading }. es.dataTable from labels/es. |
ref |
Ref<HTMLDivElement> |
— | The scroll region around the table. |
className |
string |
— | Placement, on the region. |
| anything else | <div> attributes |
— | On the region. |
What a sortAction form carries. A sort form is a GET form, and a GET form sends only its
own fields: the sort value of the button pressed (<column>:<direction>) and the hidden inputs
sortFields renders. It does not read the filters or the page from the address. An app that
filters or pages the list passes the filters in force and the page through sortFields
(sortFields={{ q: 'ada', team: 'platform', page: '1' }}), or the sort would drop them. With
sortHref the app builds each address itself, so it keeps them there.
A column’s align: 'end' is for figures, rowHeader reads its cells as the row’s name, and
hideHeader keeps the header for assistive technology and takes it off the page, for a column of
actions.
Exported types: DataTableProps, DataTableColumn, SortDirection, DataTableLabels, and the
label sets dataTableLabels.
Accessibility
Section titled “Accessibility”- A real
<table>with a<caption>,scope="col"headers and, for a column markedrowHeader,scope="row"cells. aria-sortmarks the sorted header. The arrow beside it is decoration.- A sortable header is a link or a button named by its header text. Sorting by button uses a form outside the table, so a table inside another form still works.
- The scroll region is focusable and named by the caption, so a keyboard reaches a table wider than its room.
- Loading marks the table
aria-busyand announces “Loading” once, politely. The grey bars are hidden from assistive technology. - Every link and button draws the kit’s focus ring.
Without JavaScript
Section titled “Without JavaScript”It needs none, and renders as a Server Component. Sorting is a link or a GET form: the order
lives in the address, so it survives a reload and can be shared. Keep the address the single source
of the order and pass it back as sort.
Theming
Section titled “Theming”raised, sunken, hover, border-default and border-subtle for the surfaces and lines; ink,
body, muted and primary for text; the focus rings, and the inset one on the scroll region.