Data
Table
Shows rows of records in aligned columns, such as emails, tickets or people.
Import
import { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from "@booleanpress/ui/table"Usage
Table styles the native table elements and adds nothing else: no sorting, selection or paging. It wraps the <table> in a container that scrolls sideways when the columns do not fit.
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@booleanpress/ui/table"
export function Emails() {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Recipient</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>ana@example.com</TableCell>
<TableCell>Delivered</TableCell>
</TableRow>
</TableBody>
</Table>
)
}The parts are Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell and TableCaption. For a selected row, set data-state="selected" on the TableRow: it is tinted with the primary colour. className on Table goes on the <table>, not on the scroll container.
For sorting, filtering and paging, drive the rows from your own state or a table library, and render them with these parts. Combine with Checkbox for row selection, Pagination for paging and Badge for status.
Examples
Basic
A header row, three body rows and a status badge in a cell.
Caption and footer
TableCaption names the table; TableFooter holds the totals.
Selectable rows
Row checkboxes and a select-all box that shows a dash when only some rows are chosen. Chosen rows are tinted through data-state="selected".
Empty
A single cell spans every column and says why there are no rows.
Horizontal scroll
In a narrow space the container scrolls sideways, and the cells do not wrap.
Accessibility
- Semantics
- Native
table,thead,tbody,tfoot,tr,thandtd, so a screen reader announces the row and column of each cell.TableCaptionis a nativecaption. - Labels
- Name the table with a
TableCaption, oraria-labelonTablewhen a visible caption does not fit. Give a checkbox in a row or in the header anaria-labelthat says what it selects ("Select t-1040", "Select all tickets"). An empty header cell, such as one above an action menu, needs visually hidden text. - Focus
- The table has no tab stop of its own. Controls inside cells (checkboxes, links, menus) are tab stops in reading order.
- Known limits
- Selection is shown by colour alone. The tint tells a sighted person which rows are chosen; the checkbox state (
aria-checked) tells everyone else. Keep a checkbox in each selectable row. - The scroll container is not a tab stop, so a keyboard user cannot scroll a wide table unless a control inside it takes focus. Add
tabIndex={0}, with a name, to your own wrapper if the table can have no focusable content. - There is no sorting or
aria-sort. Addaria-sorton theTableHeadyou sort by. - Cells do not wrap (
whitespace-nowrap). Long text makes the table scroll; addwhitespace-normalto a cell that should wrap.
- Selection is shown by colour alone. The tint tells a sighted person which rows are chosen; the checkbox state (
Keyboard
| Key | Behaviour |
|---|
API
Table
Renders a table and passes it every other prop.
TableHeader
Renders a thead and passes it every other prop.
TableBody
Renders a tbody and passes it every other prop.
TableFooter
Renders a tfoot and passes it every other prop.
TableHead
Renders a th and passes it every other prop.
TableRow
Renders a tr and passes it every other prop.
TableCell
Renders a td and passes it every other prop.
TableCaption
Renders a caption and passes it every other prop.
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="table-container" (Table), data-slot="table-header" (TableHeader), data-slot="table-body" (TableBody), data-slot="table-footer" (TableFooter), data-slot="table-head" (TableHead), data-slot="table-row" (TableRow), data-slot="table-cell" (TableCell), data-slot="table-caption" (TableCaption).
Theming
A row darkens on hover (bg-muted/50) and a selected row is tinted bg-primary/10. The footer is bg-muted/50.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--foreground | text |
--muted | background |
--muted-foreground | text |
--primary | background |