Table
Structured table primitive for dense product-facing data and repeatable row rhythm.
Copy a concise page brief or the full MDX source without digging through the docs shell.
| Item | Owner | Status |
|---|---|---|
| Launch issue 04 | Editorial | Ready |
| Spec revision | Product | Review |
| Shelf imagery | Studio | Queued |
The table primitives keep row rhythm, numeric alignment, and selection states consistent across denser data surfaces. They are intentionally simple wrappers around HTML table elements, with the Swiss styling work concentrated in spacing, borders, uppercase headers, row-state treatment, and a theme-derived surface scale that keeps dense views differentiated without leaving the active palette.
This pass expands the primitive so common product-table needs stay within the shipped API: denser layouts, lighter or stronger table chrome, row striping, sticky headers, and pinned or striped columns.
Installation
Purchase access, then open /account/install to issue a registry token.Usage
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"<Table>
<TableHeader>
<TableRow>
<TableHead>Item</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Launch issue 04</TableCell>
<TableCell>Ready</TableCell>
</TableRow>
</TableBody>
</Table><Table surface="soft" chrome="strong" density="dense">
<TableHeader sticky>
<TableRow>
<TableHead sticky="left">Record</TableHead>
<TableHead striped>Region</TableHead>
<TableHead numeric>Delta</TableHead>
</TableRow>
</TableHeader>
<TableBody striped>
<TableRow>
<TableCell sticky="left">BA-1024</TableCell>
<TableCell striped>North America</TableCell>
<TableCell numeric>+4</TableCell>
</TableRow>
</TableBody>
</Table>Why This Primitive Exists
Product tables need more than plain HTML defaults, but they do not need a full data-grid abstraction every time.
- Use these primitives when the information is genuinely tabular and column comparison matters.
- Keep the schema stable so users can scan down the same columns repeatedly.
- Avoid tables for short lists that are easier to read as stacked cards or items.
Examples
Basic Structure
Start with the six core building blocks and let the content determine the column widths.
| Item | Owner | Status |
|---|---|---|
| Launch issue 04 | Editorial | Ready |
| Spec revision | Product | Review |
| Shelf imagery | Studio | Queued |
Numeric Columns
The Swiss table supports both the legacy data-numeric convention and a direct numeric prop on TableHead and TableCell so counts, prices, and totals line up cleanly.
| Region | Orders | Revenue |
|---|---|---|
| North America | 148 | $42,300 |
| Europe | 96 | $31,180 |
| Asia Pacific | 74 | $19,640 |
<TableHead numeric>Revenue</TableHead>
<TableCell numeric>$42,300</TableCell>In Context
Tables become more useful when selection, hover state, and surrounding panel hierarchy all reinforce the current row. The surrounding surface can stay on theme without collapsing back to the same neutral panel every time.
Operations table
| SKU | Stock | Status |
|---|---|---|
| CH-104 | 18 | Allocated |
| CH-108 | 42 | Available |
| CH-112 | 7 | Backorder |
<TableRow data-state="selected">
<TableCell>CH-104</TableCell>
<TableCell data-numeric="true">18</TableCell>
<TableCell>Allocated</TableCell>
</TableRow>Variants
Surface, chrome, density, and row striping are now first-class controls so tables can shift between quieter and stronger product shells without rewriting the internals.
Surface, density, and row-striping can now shift without rewriting the primitive.
| Queue | Owner | Open | Ready |
|---|---|---|---|
| North archive | Research | 14 | 8 |
| Spec intake | Product | 9 | 5 |
| Asset requests | Studio | 22 | 13 |
| Launch review | Operations | 6 | 4 |
Sticky Zones
Sticky headers belong at the header layer, while pinned columns belong at the cell layer. That split keeps the API aligned with how real tables are composed.
Sticky headers and pinned columns stay readable inside a narrower viewport, while striped columns remain opt-in.
| Record | Owner | Region | State | Delta |
|---|---|---|---|---|
| BA-1024 | Operations | North America | Queued | +4 |
| BA-1042 | Research | Europe | In review | +1 |
| BA-1077 | Studio | Asia Pacific | Allocated | +7 |
| BA-1091 | Product | South America | Ready | +2 |
<TableHeader sticky />
<TableBody striped />
<TableHead sticky="left">Record</TableHead>
<TableCell sticky="left">BA-1024</TableCell>
<TableHead striped>Region</TableHead>
<TableCell striped>North America</TableCell>Guidance
Use Tables For Comparison
- Reach for a table when users need to scan several records against the same set of columns.
- Prefer cards or list items when each row has a different internal structure.
- Keep column labels short and explicit so the header reads quickly.
Respect Numeric Alignment
- Apply
data-numeric="true"to both the header and cells of numeric columns. - Use tabular values for prices, counts, and percentages so totals stay visually aligned.
- Avoid mixing freeform text into numeric columns unless the interface absolutely requires it.
Keep Row State Legible
- Use
data-state="selected"onTableRowwhen the row is actively selected. - Let hover and focus states support scanability rather than turn the table into a high-contrast grid.
- If the surface needs filtering, bulk actions, or pagination, compose those controls around the table instead of inside the cells.
Use Striping Sparingly
- Use
stripedonTableBodywhen longer datasets need extra scan support. - Use
stripedonTableHeadandTableCellonly for columns that genuinely benefit from a quieter band. - Do not stripe every row and every column at once. The table should still read through type, alignment, and shared edges first.
Keep Sticky Behavior Structural
- Use
stickyonTableHeaderfor the common sticky-header case. - Use
sticky="left"orsticky="right"onTableHeadandTableCellfor pinned columns. - Add
stickyOffsetwhen more than one pinned column needs a measured offset.
API Reference
Exports
| Export | Renders | Notes |
|---|---|---|
Table | wrapper div + table | Adds horizontal overflow handling and the outer border. |
TableHeader | thead | Applies the stronger bottom border rhythm for header rows. |
TableBody | tbody | Removes the trailing row border on the last row and can stripe rows. |
TableFooter | tfoot | Adds muted background treatment for summary rows. |
TableRow | tr | Includes hover, focus-within, and optional selected styling. |
TableHead | th | Uppercase condensed header cell with optional numeric, striped, or sticky treatment. |
TableCell | td | Default body cell spacing and text treatment with optional numeric, striped, or sticky treatment. |
TableCaption | caption | Muted caption copy below the table. |
Repo-Specific Behaviors
| Pattern | Detail |
|---|---|
data-numeric="true" | Right-aligns numbers and enables tabular alignment on TableHead and TableCell. |
numeric | Direct boolean prop alternative for the same numeric alignment behavior. |
data-state="selected" | Applies the selected row background on TableRow. |
| focus within row | Adds the stronger inset border treatment while interactive content inside the row has focus. |
striped | Available on TableBody, TableHead, and TableCell for row and column banding. |
sticky | Available on TableHeader, TableHead, and TableCell for sticky headers and pinned columns. |
stickyOffset | Sets the offset for pinned columns when more than one column is sticky on the same side. |
surface, chrome, density, layout | Available on Table to tune surface tone, border strength, row density, and layout strategy. |
All components accept the standard props for their underlying HTML elements plus className.