Skip to content
Display

Table

Rows of records with sortable headers.

import { Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption } from "@flinbu/seed";

Sortable, with a selected row. On a phone each row is a card

3 of 446 tokens
LightUsesStatus
bg-accent-solid#2563EB14Published
border-focus#2563EB0Draft
text-secondary#52525252Published
import { Badge, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@flinbu/seed";

const [dir, setDir] = React.useState<"ascending" | "descending">("ascending");
const rows = [...ROWS].sort((a, b) => (dir === "ascending" ? 1 : -1) * a.name.localeCompare(b.name));

<Table frameClassName="max-w-xl">
  <TableCaption>3 of 446 tokens</TableCaption>
  <TableHeader>
    <TableRow>
      <TableHead sort={dir} onSort={() => setDir(dir === "ascending" ? "descending" : "ascending")}>Token</TableHead>
      <TableHead>Light</TableHead>
      <TableHead align="right">Uses</TableHead>
      <TableHead>Status</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    {rows.map((r) => (
      <TableRow key={r.name} selected={r.name === "text-secondary"}>
        <TableCell className="font-mono">{r.name}</TableCell>
        <TableCell className="font-mono text-secondary">{r.value}</TableCell>
        <TableCell align="right">{r.uses}</TableCell>
        <TableCell><Badge variant={r.status === "Draft" ? "warning" : "success"} dot>{r.status}</Badge></TableCell>
      </TableRow>
    ))}
  </TableBody>
</Table>

Stays a table on phones

TokenValue
space-xs8px
space-sm12px
space-base16px
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@flinbu/seed";

<Table stackOnMobile={false} frameClassName="max-w-xs" aria-label="Spacing">
  <TableHeader><TableRow><TableHead>Token</TableHead><TableHead align="right">Value</TableHead></TableRow></TableHeader>
  <TableBody>
    {[["space-xs", "8px"], ["space-sm", "12px"], ["space-base", "16px"]].map(([t, v]) => (
      <TableRow key={t}><TableCell className="font-mono">{t}</TableCell><TableCell align="right" className="font-mono text-secondary">{v}</TableCell></TableRow>
    ))}
  </TableBody>
</Table>

Use it for

  • Lists people compare or scan: tokens, members, versions.

Use something else for

  • Layout: use grids.

Props

PropTypeDefaultDescription
density'comfortable''compact''comfortable'48 or 40 px rows.
stackOnMobilebooleantrueBelow 768px each row is a card: the first cell as its title, every other cell under its header. false keeps the table, scrolling sideways in its frame.
frameClassNamestring–Classes for the frame.
TableCell: labelstring–The header shown above the value on phones. Default the column header's text.
TableRow: selectedboolean–Neutral selection color.
TableHead: sort'ascending''descending'false–Makes the header a sort button.
TableHead: onSort() => void–Called on click.
TableHead / TableCell: align'left''center''right''left'Right-align numbers.

Accessibility

  • Real table markup with scope on headers.
  • Sortable headers are buttons and report aria-sort.
  • Below 768px rows stack into cards and keep table roles, so each value is still read with its header; the visible label above it is hidden from screen readers so it isn't read twice.