Data Table
DataTable is a fully typed, render-prop table. You define columns once with explicit cell renderers and pass row data; the component handles layout, empty state, and optional row click. All visual values come from --ds-* tokens.
Live demo
Usage
import { DataTable } from "@beacon/design-system";import type { DataTableColumn } from "@beacon/design-system";import { StatusBadge } from "@beacon/design-system";
interface Invoice { id: string; number: string; amount: number; status: "open" | "paid" | "overdue";}
const columns: DataTableColumn<Invoice>[] = [ { key: "number", header: "Invoice", render: (row) => row.number, }, { key: "amount", header: "Amount", align: "right", render: (row) => `$${row.amount.toLocaleString()}`, }, { key: "status", header: "Status", render: (row) => ( <StatusBadge tone={row.status === "overdue" ? "danger" : row.status === "paid" ? "success" : "info"}> {row.status} </StatusBadge> ), },];
<DataTable columns={columns} rows={invoices} getRowKey={(row) => row.id} onRowClick={(row) => navigate(`/invoices/${row.id}`)} empty={<span>No invoices found.</span>}/>Dense mode
For data-heavy views where vertical space is at a premium:
<DataTable columns={columns} rows={rows} getRowKey={(r) => r.id} dense />Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | DataTableColumn<T>[] | — | Column definitions. Required. |
rows | T[] | — | Row data array. Required. |
getRowKey | (row: T) => string | — | Returns a stable React key for each row. Required. |
onRowClick | (row: T) => void | undefined | If provided, rows are interactive and call this on click. |
dense | boolean | undefined | Reduces row height for data-heavy tables. |
empty | ReactNode | "No data" | Rendered in place of the body when rows is empty. |
DataTableColumn<T> shape
| Field | Type | Default | Description |
|---|---|---|---|
key | string | — | Stable column key. |
header | ReactNode | — | Column header label. |
align | "left" | "right" | "center" | "left" | Cell text alignment. |
width | string | undefined | Optional fixed CSS width (e.g. "120px", "10rem"). |
render | (row: T) => ReactNode | — | Cell renderer. Explicit render prop keeps the table fully typed. |
Design tokens used
| Token | Role |
|---|---|
--ds-color-surface-raised | Table background. |
--ds-color-border-default | Row and header dividers. |
--ds-color-content-default | Cell text. |
--ds-color-content-dim | Header text. |
--ds-color-surface-raised-2 | Row hover state. |
--ds-font-size-sm | Cell and header font size. |
--ds-space-sm / --ds-space-md | Cell padding (dense vs. normal). |
When to use
- Any list view that benefits from column headers and optional sorting.
- Data exports, invoice lists, lien project lists, notice queues.
Prefer DataTable over hand-rolling <table> elements. It keeps column definitions in one place and ensures consistent token usage across all tabular data.