Table
Rows and columns of records or of text, with a header, a footer, a caption, and a container that scrolls only when it must.
Table is a styled HTML table for data that has rows and columns: records with their figures, or
a reference of names and meanings. It renders real <table> semantics. For thousands of rows with
sorting, filtering and server paging, a data grid is the tool; for a list of label and value pairs,
a description list.
| Scheme | Participants | Contributions |
|---|---|---|
| Pension scheme 2026 | 214 | โฌ1,284,500.50 |
| Bridging scheme | 38 | โฌ96,300.00 |
| Early retirement | 7 | โฌ12,250.75 |
| Total | โฌ1,393,051.25 | |
| Setting | Meaning |
|---|---|
date | How a date is written, such as DMY_NUMERIC. |
number | The separators of a number, such as COMMA_DECIMAL_DOT_GROUP. |
// apps/docs/examples/ui/table.tsx'use client';
import {formatCurrency, formatNumber} from '@workspace/active-format';import {Code} from '@workspace/active-ui/components/composed/code';import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow,} from '@workspace/active-ui/components/primitives/table';
// Fixed figures, formatted by active-format in the language of the page.const SCHEMES = [ {name: 'Pension scheme 2026', participants: 214, contributions: 1284500.5}, {name: 'Bridging scheme', participants: 38, contributions: 96300}, {name: 'Early retirement', participants: 7, contributions: 12250.75},];const money = (amount: number) => formatCurrency({amount, currency: 'EUR'}, 'en');
const SETTINGS = [ ['dateFormat', 'How a date is written, such as DMY_NUMERIC.'], [ 'numberFormat', 'The separators of a number, such as COMMA_DECIMAL_DOT_GROUP.', ],];
/** * A data table: one row per record, numbers aligned to the right, a footer * with the totals and a caption. Below it a text table (`layout="text"`), * whose cells wrap and keep identifiers whole. */export default function TableExample() { const total = SCHEMES.reduce((sum, s) => sum + s.contributions, 0); return ( <div className="flex w-full max-w-xl flex-col gap-8"> <Table> <TableCaption>Contributions collected in 2026</TableCaption> <TableHeader> <TableRow> <TableHead>Scheme</TableHead> <TableHead className="text-right">Participants</TableHead> <TableHead className="text-right">Contributions</TableHead> </TableRow> </TableHeader> <TableBody> {SCHEMES.map((scheme) => ( <TableRow key={scheme.name}> <TableCell className="font-medium">{scheme.name}</TableCell> <TableCell className="text-right tabular-nums"> {formatNumber(scheme.participants, 'integer', 'en')} </TableCell> <TableCell className="text-right tabular-nums"> {money(scheme.contributions)} </TableCell> </TableRow> ))} </TableBody> <TableFooter> <TableRow> <TableCell colSpan={2}>Total</TableCell> <TableCell className="text-right tabular-nums"> {money(total)} </TableCell> </TableRow> </TableFooter> </Table>
<Table layout="text" scrollLabel="Settings, scrolls sideways"> <TableHeader> <TableRow> <TableHead>Setting</TableHead> <TableHead>Meaning</TableHead> </TableRow> </TableHeader> <TableBody> {SETTINGS.map(([name, meaning]) => ( <TableRow key={name}> <TableCell> <Code>{name}</Code> </TableCell> <TableCell>{meaning}</TableCell> </TableRow> ))} </TableBody> </Table> </div> );}Usage#
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow,} from '@workspace/active-ui/components/primitives/table';
<Table> <TableHeader> <TableRow> <TableHead>Scheme</TableHead> <TableHead className="text-right">Participants</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>Pension scheme 2026</TableCell> <TableCell className="text-right tabular-nums">214</TableCell> </TableRow> </TableBody></Table>;Two layouts#
layout="data"(the default): every cell on one line, vertically centred, at the compact size. For records and figures.layout="text": cells wrap and align to the top, at the base text size. For a reference or a catalogue whose cells hold sentences. Identifiers inCodestay whole while the table fits; only when it does not are they split at their readable break points (_,., camelCase), never inside a word. This site renders every Markdown table this way.
In both layouts a table that does not fit its column scrolls inside its own container, never the
page. While it scrolls, the container is a keyboard stop; with scroll it is also a named
region.
Anatomy#
Table: the<table>in its container.layoutandscroll.Label Table,Header Table,Body Table:Footer <thead>,<tbody>,<tfoot>.Table,Row Table(Head <th>),Table(Cell <td>),Table(Caption <caption>, below the table).
What your application provides#
Formatted values: numbers, amounts and dates come formatted, for example with active-format. Align figures to the right with
text-andright tabular-.nums scope="col"on header cells of a complex table, and a caption or a heading that says what the table holds.scrollfor a table that may be wider than its column, in your reader's language.Label
Accessibility and keyboard#
Real table semantics: screen readers announce rows, columns and headers.
A container that scrolls takes focus, so the keyboard can scroll it with the arrow keys; a table that fits adds no tab stop.
API#
Import from @workspace/
Props
- Type
"data""text"- Default
'data'
data: every cell on one line, vertically centred, compact. text: cells wrap and align to the top at the base size, and identifiers in Code stay whole while the table fits.
- Type
string
The name of the scroll container while the table is wider than it is, such as "Table, scrolls sideways"; it then becomes a named region.
Other props, such as the standard attributes of the underlying element, className and ref, are passed through.
Other parts#
Parts that take only their elementโs attributes
Table: the attributes of aHeader <thead>, with className and ref.Table: the attributes of aBody <tbody>, with className and ref.Table: the attributes of aHead <th>, with className and ref.Table: the attributes of aRow <tr>, with className and ref.Table: the attributes of aCell <td>, with className and ref.Table: the attributes of aCaption <caption>, with className and ref.
This page adapts the Table documentation of shadcn/ui (MIT licence) to this package; see Third-party notices.