Tables
Rows sharing one schema: Table (React Aria’s grid), TableCard (the card shell), and TableRowActionsDropdown. Two sizes, set on the card.
Tables
Rows sharing one schema: Table (React Aria’s grid), TableCard (the card shell), and TableRowActionsDropdown. Two sizes, set on the card.
Demo
The two parts the sheet gives their own symbol set: every cell type, and the header cell, both on the size axis.
Olivia Rhyeolivia@untitledui.com |
Parts here, whole tables in the contextual demo
Table cell (1222:107305, fifteen Types over two sizes and two states) and Table header cell (1221:107933, three shapes over two sizes) — and this Demo is those two, nothing more. An assembled table is a composition rather than a component: it is a card header, a filters band, the table, and a pagination footer, and it lives on the contextual demo where it can be a real screen.The controls are the component's own properties
type, size and state, Table cell exposes three booleans — leadAction, leadText and supportingText — and each Type wires up a subset. The four identity Types take all three; Avatar group and both Trends take supportingText alone, where it is the “10 users” count and the “$1,800” value. The other eight take none: the “+4” on Badges multiple, the “60%” beside a progress bar and the third and fourth action icon are drawn into the symbol, so the rail does not offer to remove them.A lead action is one of three controls
Table cell lead action (9400:570197), which is its own set of three — a checkbox, a radio, or a toggle — so the Demo switches between them. A real table is the other way round: selectionMode inserts a selection column the kit owns, and it draws a checkbox and nothing else. A radio or a toggle is a column you place yourself, which is what the Lead actions section below is about.The header cell is white on the sheet, gray here
Table header cell (1221:107933) draws itself on bg-primary, but every composed table on the sheet has a bg-secondary header row — sampled at #f8fafc on Team members, Customers and Files, and white only on the alternating-fills variant. The kit draws the default, so the specimen is gray. Everything else matches to the pixel: 152 / 104 / 68 wide at md and 144 / 96 / 68 at sm, 44 and 40 tall, 24/12 and 20/8 paddings, a 12px semibold text-quaternary label 4px from a 12px arrow.The lead action is not part of the header cell
Table.Header inserts when selectionModeis multiple. The two render the same row and disagree about how many cells it has — which is why the sheet’s first column measures 44px wider than the one you declare. The column widths section has the correction.Contextual demo
Six working screens: the sheet’s four compositions, an empty result set, and a table wider than its column.
This page is also a consumer
DataTable wraps Table at size="md", in _components/prose.tsx.The family
Three exports; the root carries Header, Head, Row, Cell, and Body, and TableCard carries Root and Header.
| Component | Description | Import from |
|---|---|---|
| Table | The root: React Aria’s Table inside a keyboard-focusable scroll region. Selection mode, sorting state, and the accessible name live here. Its own size prop is shadowed by the card context — see the Code tab’s defects. | @/components/application/table/table |
| Table.Header | The header row: bg-secondary with a hairline divider drawn as a pseudo-element, and the selection column inserted on its own when selection is on. | @/components/application/table/table |
| Table.Head | One column header: a label, an optional named help tooltip, and the sort glyphs when the column allows sorting. Reads its size from the context only. | @/components/application/table/table |
| Table.Row | One row: 72px at md and 64px at sm, hover and selected both painted bg-secondary, with the divider under every row — the last one included. | @/components/application/table/table |
| Table.Cell | One cell: text-sm in text-tertiary with the size’s paddings. Everything inside it — avatars, badges, progress, actions — is caller composition. | @/components/application/table/table |
| Table.Body | React Aria’s TableBody re-exported untouched: static children or an items collection, plus renderEmptyState, with no kit styling of its own. | @/components/application/table/table |
| TableCard.Root | The card shell: bg-primary, a 12px radius, shadow-xs, and a 1px inset outline. It owns the size context every part reads, which makes it the one place the size axis works family-wide. | @/components/application/table/table |
| TableCard.Header | The card’s title bar: an h2 title, an optional badge and description, and a trailing slot pinned top-right at every width. | @/components/application/table/table |
| TableRowActionsDropdown | A fixture, not a configurable component: a dots button opening a fixed three-item menu (Edit, Copy link, Delete). Build your own Dropdown for anything else. | @/components/application/table/table |
Built from
Five pieces make up the family; four have their own docs page.
Component | Where it’s used here |
|---|---|
| Checkbox | The selection column, at size md — a 20px box — with slot="selection", which is how React Aria names it “Select” per row and “Select All” in the header. |
| Badge | TableCard.Header’s badge prop when given a string: gray, modern, sm, 6px after the title. |
| Tooltip | Table.Head’s tooltip prop: a 16px help icon in a TooltipTrigger, named “More information” since 2026-08-23. |
| Dropdown | TableRowActionsDropdown: Dropdown.Root, DotsButton, Popover, and Menu around three fixed items. |
Sizes
Two sizes on TableCard.Root, read through context: md is 44px over 72px rows at 24px insets; sm 40px over 64px at 20px.
Team members
3 membersManage the people in this workspace.
Name | Role | Status |
|---|---|---|
Olivia Rhye@olivia | Product designer | Active |
Phoenix Baker@phoenix | Product manager | Active |
Lana Steiner@lana | Frontend developer | Active |
Team members
3 membersManage the people in this workspace.
Name | Role | Status |
|---|---|---|
Olivia Rhye@olivia | Product designer | Active |
Phoenix Baker@phoenix | Product manager | Active |
Lana Steiner@lana | Frontend developer | Active |
The card is the size switch
TableCard.Root size="sm" resizes everything inside it — header and row heights, cell and card-header paddings, the selection column — because every part reads the card’s context. Header, Row, and Cell also take their own size for row-level exceptions, but Head does not, and the root’s size prop never takes effect at all.Cell types
Fifteen types, both sizes. The kit ships none of them — a cell is a container, and each one is composed from kit parts.
Cell type | The composition |
|---|---|
TextIdentity | Olivia Rhyeolivia@untitledui.com |
AvatarIdentity | Olivia Rhyeolivia@untitledui.com |
File type iconIdentity | Tech requirements.pdf200 KB |
Payment methodIdentity | Visa ending in 1234Expiry 06/2028 |
BadgeStatus | Active |
Badges multipleStatus | LabelLabelLabel+4 |
Trend positiveData | $1,800Up 20% |
Trend negativeData | $1,800Down 20% |
Progress barData | 60% |
Star ratingsData | 4 out of 5 |
Avatar groupData | 10 users +5 |
Select dropdownControls | |
Action buttonsActions | |
Action iconsActions | |
Action dropdown iconActions |
Cell type | The composition |
|---|---|
TextIdentity | Olivia Rhyeolivia@untitledui.com |
AvatarIdentity | Olivia Rhyeolivia@untitledui.com |
File type iconIdentity | Tech requirements.pdf200 KB |
Payment methodIdentity | Visa ending in 1234Expiry 06/2028 |
BadgeStatus | Active |
Badges multipleStatus | LabelLabelLabel+4 |
Trend positiveData | $1,800Up 20% |
Trend negativeData | $1,800Down 20% |
Progress barData | 60% |
Star ratingsData | 4 out of 5 |
Avatar groupData | 10 users +5 |
Select dropdownControls | |
Action buttonsActions | |
Action iconsActions | |
Action dropdown iconActions |
Sixty symbols, thirty rows
bg-secondary for both states, which is why the two galleries above cover the whole set. Hover any row to see it. Every composition is built from the kit part it names on the recipes table — a change in Badge or Avatar reaches this page without an edit here.Column header labels
A label, an optional help icon, and four sort states. The kit derives the arrow from React Aria rather than a prop.
Company |
|---|
Company |
|---|
Company |
|---|
Company |
|---|
Company |
|---|
Company |
|---|
Company |
|---|
Company |
|---|
Sixteen symbols, eight live cells
_Table header label set is a help icon crossed with four arrows crossed with a hover state. Hover is live on every cell above, so the eight here cover all sixteen. One naming difference: the sheet draws a separate arrow-up glyph, and the kit rotates the down arrow 180° — identical on screen. Both glyphs are aria-hidden since 2026-08-23, because React Aria’s aria-sort already says which way the column runs, and the help trigger is named “More information”.Lead actions
The control that opens a row. The kit inserts a checkbox for you; the sheet’s other two are yours to place.
Control | Type | What it means |
|---|---|---|
| Checkbox | Select many rows. The only one the kit inserts for you, at selectionMode multiple. | |
| Radio | Pick exactly one row. selectionMode single still draws a checkbox, so place this yourself. | |
| Toggle | Switch the row's own state — enabled, published, live. Not selection at all. |
Only one of the three is automatic
selectionMode="multiple" makes Table.Header and Table.Row insert the checkbox column themselves, sized and padded per the sheet, with React Aria naming the boxes “Select” and “Select All”. selectionMode="single" still draws a checkbox rather than a radio, so a single-choice table needs a column of your own — and a toggle is not selection at all, it is the row’s own state.Column widths
Every composition is a fixed layout over the 1216px frame. The identity column leads, but never takes more than a third.
table-fixed is what makes a width bind
get_metadata, so these are the frame’s own auto-layout widths rather than anything measured from a screenshot. Reproducing them takes table-fixed: under a table’s default auto layout a browser treats a width as a hint and re-solves it from the content, which is how one className="w-full" column ends up taking three-quarters of the row. The Guidelines tab has the rule and what it looks like when it goes wrong.Selection and sorting
Selection inserts its own checkbox column; sorting is a controlled SortDescriptor. The demo holds real product state.
Team members
5 membersManage the people in this workspace.
Name | Role | Status | ||
|---|---|---|---|---|
| Candice Wu | Fullstack developer | Active | ||
| Demi Wilkinson | Backend developer | Invited | ||
| Lana Steiner | Frontend developer | Active | ||
| Olivia Rhye | Product designer | Active | ||
| Phoenix Baker | Product manager | Active |
Selected is hover’s twin, on purpose
bg-secondary: the sheet folds them into one combined Hover/selected state, and the kit follows. The checkbox and aria-selected carry the real state. The last row keeps its divider since 2026-08-23: on the sheet it separates the rows from the card’s pagination footer, which the compositions above now show.Alternating fills
Not a variant: the header goes bg-primary, odd rows take bg-secondary, and the line dividers stay. One className each.
Member | Role | Teams | Status |
|---|---|---|---|
Olivia Rhye@olivia | Product designer | DesignProduct+4 | Active |
Phoenix Baker@phoenix | Product manager | ProductMarketing+2 | Active |
Lana Steiner@lana | Frontend developer | Engineering+3 | Active |
Demi Wilkinson@demi | Backend developer | Engineering | Invited |
A Figma-only variant
bg-primary belongs to this alternating variant, not to the default. On odd rows the hover tint disappears into the stripe, which is one reason the kit leaves this as a caller composition.Overflow
The sheet’s mobile answer is horizontal overflow. The kit wraps every table in a keyboard-reachable scroll region.
Name | Teams | Usage | Trend |
|---|---|---|---|
Olivia Rhye@olivia | DesignProduct+4 | 82% | Up 12% |
Phoenix Baker@phoenix | ProductMarketing+2 | 64% | Up 8% |
Lana Steiner@lana | Engineering+3 | 47% | Down 3% |
Named after the table
role="region" and derives its name from the table’s: aria-label of "Team usage" becomes "Team usage (scrollable)", with "Scrollable table" as the unnamed fallback.Row actions
Three patterns from the sheet: two named buttons, a strip of icon buttons, and the overflow menu. Pick one per table.
Name | Buttons | Icons | Overflow |
|---|---|---|---|
Demi Wilkinson@demi | |||
CW Candice Wu@candice | |||
Natali Craig@natali |
Every icon needs its own name
Edit Demi Wilkinson, not Edit. The same rule is why TableRowActionsDropdown took a label on 2026-08-26: without it every row’s menu announced “Open menu”. The sheet’s icon cell draws four glyphs; its Team members composition uses two of them.