Skip to the content
BooleanPress UI

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.

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, th and td, so a screen reader announces the row and column of each cell. TableCaption is a native caption.
Labels
Name the table with a TableCaption, or aria-label on Table when a visible caption does not fit. Give a checkbox in a row or in the header an aria-label that 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. Add aria-sort on the TableHead you sort by.
  • Cells do not wrap (whitespace-nowrap). Long text makes the table scroll; add whitespace-normal to a cell that should wrap.

Keyboard

Keyboard
KeyBehaviour

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.

Theme tokens
TokenUsed for
--foregroundtext
--mutedbackground
--muted-foregroundtext
--primarybackground