Skip to content

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

PropTypeDefaultDescription
columnsDataTableColumn<T>[]—Column definitions. Required.
rowsT[]—Row data array. Required.
getRowKey(row: T) => string—Returns a stable React key for each row. Required.
onRowClick(row: T) => voidundefinedIf provided, rows are interactive and call this on click.
densebooleanundefinedReduces row height for data-heavy tables.
emptyReactNode"No data"Rendered in place of the body when rows is empty.

DataTableColumn<T> shape

FieldTypeDefaultDescription
keystring—Stable column key.
headerReactNode—Column header label.
align"left" | "right" | "center""left"Cell text alignment.
widthstringundefinedOptional fixed CSS width (e.g. "120px", "10rem").
render(row: T) => ReactNode—Cell renderer. Explicit render prop keeps the table fully typed.

Design tokens used

TokenRole
--ds-color-surface-raisedTable background.
--ds-color-border-defaultRow and header dividers.
--ds-color-content-defaultCell text.
--ds-color-content-dimHeader text.
--ds-color-surface-raised-2Row hover state.
--ds-font-size-smCell and header font size.
--ds-space-sm / --ds-space-mdCell 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.