Table

Data table composed from the real table elements, so semantics, keyboard navigation and screen-reader support come from the browser.

DeployBranchStatusWhen
4f2a1cmainReady2 hours ago
9b7e30fix/loginBuilding5 hours ago
1d8c55mainFailedyesterday

Parts

ComponentElementDescription
TabletableWraps itself in a horizontal scroll container.
TableHeadertheadHeader group, with a bottom border.
TableBodytbodyBody group, rows divided by borders.
TableRowtrRow, with a hover tint.
TableHeadthHeader cell.
TableCelltdBody cell, muted by default.
TableCaptioncaptionDescription below the table.

Every part accepts className and forwards all native attributes.

Common patterns

<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Deploy</TableHead>
      <TableHead className="text-right">When</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    {deploys.map((d) => (
      <TableRow key={d.id}>
        <TableCell>{d.id}</TableCell>
        <TableCell className="text-right">{d.when}</TableCell>
      </TableRow>
    ))}
  </TableBody>
</Table>

Notes

Table renders its own overflow-x-auto wrapper. A table is the one piece of content that genuinely cannot reflow on a narrow screen — the alternative is cells squeezed to two characters wide, which is worse than scrolling.

Right-align numeric columns with className="text-right" on both the head and the cells, and consider tabular-nums so the digits line up.

There is no sorting, filtering, or pagination here. Those are application concerns with real design decisions behind them; a copy-paste table that guessed at them would be wrong more often than right.