Components / data-display

Table

Displays records in rows and columns for scanning and comparison.

import { Table } from '@basiiik/ui';

The snippet an agent gets

From get_component_snippet, with the required props filled in from the spec. Every snippet is type-checked against the library before it is shipped.

import { Table, TableBody, TableCell, TableRow } from '@basiiik/ui';

<Table><TableBody><TableRow><TableCell>Invoice 042</TableCell></TableRow></TableBody></Table>
  • Compose Table, TableHeader, TableBody, TableRow, TableHeaderCell, TableCell. density on Table flows to every cell.
  • Compose with: avatar, badge, table-row.
  • Storybook: Data display/Table.

Props

PropTypeNotes
density"compact" | "comfortable"Default "comfortable"
maxHeightstring | number
childrenReactNode

Other props

PropTypeWhat it does
captionReactNodeVisible description shown above the table. Also names it. Without it, pass aria-label.

States. Compose Table, TableHeader, TableBody, TableRow, TableHeaderCell, TableCell. density on Table flows to every cell.

Native attributes such as className, id and data-* are forwarded to the root element.

Parts

TableHeader

Wraps the header row (<thead>). A TableRow inside it becomes a header row by itself, so it needs no type.

<TableHeader><TableRow><TableHeaderCell>Name</TableHeaderCell></TableRow></TableHeader>

TableBody

Wraps the body rows (<tbody>).

<TableBody><TableRow><TableCell>Ada</TableCell></TableRow></TableBody>

TableHeaderCell

A column header. Give it sort (the current direction: ascending, descending or none) and onSort to make it a sortable button that sets aria-sort. align="end" right-aligns a numeric column. hideBelow="md" hides the column when the table's container is narrower than 640px (sm 480, lg 800); pin="end" keeps it in view while the table scrolls sideways. Set both on the header cell and on every TableCell of that column.

<TableHeaderCell sort="ascending" onSort={() => undefined}>Name</TableHeaderCell>

TableHeaderCell props

PropTypeWhat it does
sort"none" | "ascending" | "descending"Current sort direction. Sets aria-sort and, with onSort, makes the header a button.
onSort() => void
align"start" | "end"
hideBelow"sm" | "md" | "lg"Hides this column when the table's container is narrower than sm 480px, md 640px or lg 800px. Set it on the header cell and on every cell of the column.
pin"start" | "end"Keeps this column in view at the start or the end while the table scrolls sideways. Set it on the header cell and on every cell of the column.

TableCell

A body cell. align="end" right-aligns numbers. Repeat the column's hideBelow and pin from its TableHeaderCell on every cell.

<TableCell align="end" hideBelow="md">42</TableCell>

TableCell props

PropTypeWhat it does
align"start" | "end"Right-align numbers.
hideBelow"sm" | "md" | "lg"Same as on TableHeaderCell: set it on every cell of the column.
pin"start" | "end"Same as on TableHeaderCell: set it on every cell of the column.

Use it when

  • Compare structured records across several attributes
  • A long list of records in a bounded area, with a header that stays in view (maxHeight)
  • Data that must work in a narrow panel or on a phone: hide the less important columns and keep the row's name

Do not use it when

  • Layout
  • Simple one-attribute lists (use List Item)
  • A phone-first list where each record needs several lines (use List Item or Card in a stack)

Rules for agents

  • Compose Table > TableHeader and TableBody > TableRow > TableHeaderCell or TableCell
  • Name every Table: a visible caption, or aria-label when there is none
  • Right-align numbers with align="end" on both the TableHeaderCell and its TableCells
  • For sortable columns, pass sort and onSort on the TableHeaderCell; only one column is sorted at a time
  • Use density="compact" for dense admin views; comfortable is the default
  • Show an Empty State in place of the rows when there is no data, and Pagination below long tables
  • On narrow containers hide the less important columns with hideBelow="sm" (below 480px), "md" (below 640px) or "lg" (below 800px) on the TableHeaderCell and on every TableCell of that column; keep the column that identifies the row (usually the first) and the actions always visible
  • Do not hide a column that holds the only way to do something (a status badge people filter by, an action); move it or pin it instead
  • Keep a column in view while the table scrolls sideways with pin="start" (the name) or pin="end" (row actions) on the header cell and on every cell of that column; pin at most one column on each side
  • For a long table inside a page section set maxHeight (a number of px, or a CSS length): the body scrolls and the header row stays in view; leave it off when the page itself scrolls
  • Put row actions in one last column with pin="end", a visually hidden header ("Actions") and a single Dropdown Menu or icon button per row
  • Do not wrap the table in your own overflow-x container: it already has one

Avoid

  • Using a Table for layout
  • A Table for a list with a single attribute (use List Item)
  • Header cells that are not TableHeaderCell, so columns have no headers for screen readers
  • Sorting by clicking a column without showing the sort direction
  • Putting several actions as text links in every row instead of one Dropdown Menu
  • Hiding columns with your own media queries or display:none (use hideBelow, which follows the table's container)
  • hideBelow on the header cell but not on the cells of the column (or the reverse): the columns no longer line up
  • Pinning more than one column on a side, or a wide column (a pinned column should be narrow)
  • A Table with maxHeight and no caption or aria-label: the scrolling region has no name

Writing the content

  • Column headers are short nouns: 'Name', 'Status', 'Amount'
  • Use the same unit and format down a column, and put the unit in the header
  • Use sentence case

Keyboard

  • Interactive cells and row actions follow Tab order
  • A table that scrolls is one extra Tab stop (the scroll region); arrow keys, Page Up/Down and Home/End then scroll it

Accessibility

  • Use <th scope> for headers
  • aria-sort on sortable column headers
  • Provide a caption or aria-label
  • A table that overflows (sideways, or taller than maxHeight) becomes a region named by its caption or aria-label and takes focus, so a keyboard can scroll it; one that fits is not in the tab order
  • A column hidden with hideBelow is removed from the accessibility tree too: do not hide the column that identifies the row

Colour tokens it reads

color.bg.brand.subtlecolor.bg.mutedcolor.bg.subtlecolor.bg.success.subtlecolor.bg.surfacecolor.border.defaultcolor.border.subtlecolor.text.brandcolor.text.primarycolor.text.secondarycolor.text.success

Related

data-display 2 Figma variants Try it in the live demo