Table

A type-safe data table with custom cells, sortable headers, and expandable rows.

Basic table

createTable<Row>() returns a table bound to one row type, so every column callback is typed. Call it once at module scope, not during render.

getValue returns the content of a default cell. renderCell returns the whole <td>, so its classes are up to you.

NameOwnerStatusUpdated
Visibility reportJason
Ready
Today
Competitor briefMaya
Draft
Yesterday
Citation reviewPriya
Needs review
Monday

Sortable columns

The consumer owns the sort. Set sortDirection on the sorted column so the header gets aria-sort.

Status
Citation reviewPriyaMonday
Needs review
Competitor briefMayaYesterday
Draft
Visibility reportJasonToday
Ready

Expandable rows

Clicking a row, or pressing Enter or Space while it has focus, calls onToggleExpand. Keep the expanded keys in state and pass them to expandedRows. Use isRowExpandable to turn expansion off for some rows. Setting onRowClick replaces the expand toggle.

NameOwnerStatus

Action cells

align applies to the header cell and to cells rendered from getValue. A cell from renderCell sets its own alignment. Button is a block-level flex container, so wrap it in a flex justify-end container to line it up with a right-aligned header.

NameStatusActions
Visibility report
Ready
Competitor brief
Draft
Citation review
Needs review

Table Properties

dataRequired
T[]

Rows to render.

rowKey
keyof T((row: T, index: number) => React.Key)

Property or function that returns a stable row key.

Default: index

aria-label
string

Accessible name for the table.

aria-labelledby
string

Id of the element that names the table.

expandedRows
React.Key[]

Keys of the rows that are expanded.

Default: []

onToggleExpand
(rowKey: React.Key, isExpanded: boolean) => void

Called when a row is expanded or collapsed.

isRowExpandable
(row: T) => boolean

Returns false for rows that should not expand.

onRowClick
(row: T) => void

Called when a row is clicked. Replaces the expand toggle.

isLoading
boolean

Shows loadingState, or skeleton rows when loadingState is not set.

Default: false

loadingState
ReactNode

Content shown while loading.

placeholderRows
number

Number of skeleton rows while loading, and of rows the empty state fills.

Default: 5

emptyState
ReactNode

Content shown when data is empty. Defaults to No data found.

centeredEmptyState
boolean

Centers emptyState in the space below the header instead of in the first row.

Default: false

density
'default''comfortable'

comfortable fixes a 40px header row and 56px body rows.

Default: default

headerWeight
'medium''regular''mini'

Typography of the header cells. Defaults to mini when density is comfortable.

Default: medium

hideHead
boolean

Hides the header row.

Default: false

fixed
boolean

Uses a fixed table layout, so column widths do not follow content.

Default: false

fixedHeader
boolean

Keeps the header pinned while the body scrolls.

Default: false

fixedFooter
boolean

Keeps Table.Footer pinned to the bottom while the body scrolls.

Default: false

disableCardStyles
boolean

Removes the card border and background around the table.

Default: false

renderRows
(data: T[]) => ReactNode[]

Renders the body rows yourself instead of from the columns.

className
string

Additional classes for the table element.

wrapperClassName
string

Additional classes for the wrapper.

headClassName
string

Additional classes for the thead element.

rowClassName
string

Additional classes for every body row.

Table.Column Properties

idRequired
string

Unique column identifier. Without getValue or renderCell, the cell shows row[id].

label
ReactNode

Header content.

getValue
(row: T, index: number, id: string) => ReactNode

Returns the cell content inside the default cell.

renderCell
(row: T, index: number, id: string) => ReactNode

Renders the whole td for full control.

renderHeader
(column: TableColumnProps<T>) => ReactNode

Renders the whole th for full control.

loadingCell
ReactNode

Cell content while isLoading. Defaults to a full-width skeleton.

sortDirection
'asc''desc'

Active sort direction. Sets aria-sort on the header cell so screen readers announce the sort. Set it only on the sorted column.

align
'left''center''right'

Text alignment of the header cell and of cells rendered from getValue.

Default: left

className
string

Additional classes for the header cell and the body cells.

cellClassName
string

Additional classes for the body cells.

headerClassName
string

Additional classes for the header cell.

headerColSpan
number

Number of columns the header cell spans.

Table.ExpandableRow Properties

render
(row: T, index: number) => ReactNode

Content shown in one full-width row below an expanded row.

renderRows
(row: T, index: number) => ReactNode

Returns one or more tr elements shown below an expanded row. Use instead of render.

Table.Footer Properties

children
ReactNode

Footer content, such as pagination.

className
string

Additional classes for the footer.