Skip to content

Table

Table is a token-styled data table with declarative columns, for the tabular list surfaces (CRM contacts, deals) that simple rows don’t fit. It renders a real <table> for semantics, with a sticky header and rows that hover-tint and can be clickable. Sorting, selection, and virtualization are out of scope; compose Pagination for paging. The preview below is the real component from @nimblebrain/synapse/ui, live.

import { Table, type Column } from "@nimblebrain/synapse/ui";
const columns: Column<Person>[] = [
{ key: "name", header: "Name", render: (p) => p.name },
{ key: "deals", header: "Deals", align: "right", render: (p) => p.deals },
];
<Table data={people} columns={columns} rowKey={(p) => p.id} />;

Each column is declared once. Pass onRowClick to make rows clickable and keyboard-operable, and empty to render a placeholder when data is empty.

<Table
data={people}
columns={columns}
rowKey={(p) => p.id}
onRowClick={(p) => open(p)}
empty={<EmptyState title="No contacts yet" />}
/>
Prop Type Default
data T[] None
columns Column<T>[] None
rowKey (row: T, index: number) => string | number None
onRowClick (row: T, index: number) => void None
empty ReactNode None
…rest HTMLAttributes<HTMLTableElement> None

Each entry in columns describes one column.

Field Type Default
key string None
header ReactNode None
render (row: T, index: number) => ReactNode None
align "left" | "right" | "center" "left"
width number | string None
  • Pagination: page a long table.
  • ListRow: a lighter row for non-tabular lists.
  • Badge: render inside a status column.