Table

Composable React data table with header, body, footer, caption, sortable and filterable headers, selectable rows, sizes, striping, and a sticky header.

Build a Table from Header, Body, Row, Head, and Cell parts. Cell content is whatever you compose; headers gain sortable and filterable affordances, with the logic in your code.

When to use

Use Table for records with several attributes that users compare, sort, or select: applications, invoices, users. Keep the logic in your code and use the header affordances to expose it.

Use StructuredList for simple lists and DescriptionList for a single record.

Examples

Minimal table

Composed cells

Sortable columns

Selectable rows (controlled)

Props

Props declared by Table. Native attributes of the underlying element pass through.

<Table>

PropTypeDefaultDescription
size"sm" | "md" | "lg"
stripedboolean
containedboolean
stickyHeaderboolean
aria-labelstringAccessible name for the scroll region wrapping the table. Strongly recommended: a wide table scrolls horizontally, and a named, focusable region lets keyboard and screen-reader users find and scroll it. When provided, the wrapper becomes role="region" tabindex="0"; when omitted, it degrades to a plain scroll container and a dev warning fires. Note: this names the region, not the <table> - use <TableCaption> for the table's own name.
aria-labelledbystringAccessible name for the scroll region, by id reference. See aria-label.
maxHeightstring | numberCaps the scroll region's block-size (number → px) so the body scrolls vertically within it. Required for stickyHeader to engage - sticky needs a height-constrained, scrollable ancestor; without it the region grows to content height and the header has nothing to stick to.

<TableRow>

PropTypeDefaultDescription
selectedbooleanVisually highlights the row and sets data-state="selected". Selection semantics for assistive tech come from a checkbox in the cell (see the DataTable recipe), not from the row.

<TableHead>

PropTypeDefaultDescription
align"center" | "start" | "end"
sortablebooleanRenders the column as sortable: wraps content in a button and sets aria-sort. Sort logic is the consumer's - wire onClick.
sortDirectionfalse | "desc" | "asc"Current sort direction, or false when unsorted.
sortLabelstringVisually-hidden, caller-localized cue appended to the sort button's accessible name (e.g. "activate to sort ascending"). aria-sort already conveys state, but a focused button otherwise announces only its column label; this adds the action cue. Kept as a prop (not hard-coded text) so the design system stays language-neutral - pass Arabic in RTL. Only used when sortable. Typed string (not ReactNode) so interactive content can't be hidden into a keyboard-reachable, invisible trap.
filterablebooleanRenders the column's filter toggle: an icon-only funnel button sharing the sort icon-box treatment, with aria-pressed. Filter logic is the consumer's - wire onClick. Takes precedence over sortable.
filterActivebooleanWhether the filter is currently applied - drives aria-pressed and the active (filled) icon-box.
filterLabelstringVisually-hidden, caller-localized name for the icon-only filter button (e.g. "Filter"). Required with filterable so the toggle has an accessible name; a dev warning fires when missing.
onClickreact.MouseEventHandler<HTMLButtonElement>Click handler bound to the sort/filter button (only rendered when sortable or filterable).
disabledbooleanDisables the sort/filter button (renders the SDGA Disabled icon-box state).

<TableCell>

PropTypeDefaultDescription
align"center" | "start" | "end"

Accessibility

Table renders a native <table>; add a TableCaption to name it. The scroll wrapper becomes a focusable role="region" when you pass aria-label, so keyboard users can scroll wide tables.

Sortable headers expose aria-sort, and the toggle buttons announce their state. Selectable rows use real checkboxes with labels.