Data display
Table
The dense, sortable grid that backs every list view — tasks, members, invoices. Column sorting, row selection with bulk actions, rich cells, and two densities, dressed in the system's badges, avatars, and checkboxes.
npx shadcn@latest add @orbit/tableOverview
Click a header to cycle ascending → descending → unsorted; the active column shows a blue arrow and sets aria-sort. Selecting rows tints them, swaps the toolbar for a bulk-action bar with a live count, and the header checkbox toggles all with a tri-state indeterminate when partial.
| Ship onboarding flowORB-1428 | In progress | High | SCSam Chen | Jun 30 | 8 | ||
| Redesign empty statesORB-1431 | To do | Medium | PNPriya Nair | Jul 2 | 5 | ||
| Fix board drag jankORB-1419 | In review | Urgent | ARAlex Rivera | Jun 26 | 3 | ||
| Automation rules v1ORB-1402 | In progress | High | JLJordan Lee | Jul 8 | 13 | ||
| Export to CSVORB-1390 | Done | Low | MSMateo Silva | Jun 20 | 2 | ||
| Keyboard shortcuts passORB-1377 | To do | Medium | DPDana Park | Jul 11 | 5 |
States
The empty slot renders across all columns when rows is empty — hand it an EmptyState. While data loads, render the Skeleton library's table preset in its place so the page doesn't reflow.
No tasks yetTasks assigned to this project will show up here. Create one to get started. | |||||
Rich cells
Each column renders its own cell — not just text. These reuse the exact Badge, Avatar, and priority treatments from elsewhere in the library, composed here with the low-level Table / TableRow / TableCell parts. Numbers right-align with tabular figures; text and rich cells left-align for a clean rag.
| Task | Status | Priority | Assignee | Est. |
|---|---|---|---|---|
| Ship onboarding flowORB-1428 | In progress | High | SCSam Chen | 8 |
| Redesign empty statesORB-1431 | To do | Medium | PNPriya Nair | 5 |
| Fix board drag jankORB-1419 | In review | Urgent | ARAlex Rivera | 3 |
Density
Compact tightens rows from 52px to 40px for power users scanning long lists. No toolbar, footer, or selection here — the table also works bare.
| Ship onboarding flowORB-1428 | In progress | High | SCSam Chen | Jun 30 | 8 |
| Redesign empty statesORB-1431 | To do | Medium | PNPriya Nair | Jul 2 | 5 |
| Fix board drag jankORB-1419 | In review | Urgent | ARAlex Rivera | Jun 26 | 3 |
| Automation rules v1ORB-1402 | In progress | High | JLJordan Lee | Jul 8 | 13 |
| Export to CSVORB-1390 | Done | Low | MSMateo Silva | Jun 20 | 2 |
| Keyboard shortcuts passORB-1377 | To do | Medium | DPDana Park | Jul 11 | 5 |
Sticky header
stickyHeader pins the header row to the top of the scroll container — pair it with a max-height on the table's scroll area via containerClassName.
| Ship onboarding flowORB-1428 | In progress | High | SCSam Chen | Jun 30 | 8 | |
| Redesign empty statesORB-1431 | To do | Medium | PNPriya Nair | Jul 2 | 5 | |
| Fix board drag jankORB-1419 | In review | Urgent | ARAlex Rivera | Jun 26 | 3 | |
| Automation rules v1ORB-1402 | In progress | High | JLJordan Lee | Jul 8 | 13 | |
| Export to CSVORB-1390 | Done | Low | MSMateo Silva | Jun 20 | 2 | |
| Keyboard shortcuts passORB-1377 | To do | Medium | DPDana Park | Jul 11 | 5 | |
| Notification digestsORB-1361 | In review | Medium | SCSam Chen | Jul 14 | 5 | |
| Mobile nav polishORB-1355 | To do | Low | PNPriya Nair | Jul 18 | 3 | |
| Audit log v2ORB-1348 | In progress | High | ARAlex Rivera | Jul 21 | 8 | |
| SSO edge casesORB-1340 | To do | Urgent | JLJordan Lee | Jul 22 | 5 | |
| Bulk import wizardORB-1333 | Done | Medium | MSMateo Silva | Jun 12 | 8 | |
| Rate-limit dashboardsORB-1327 | In review | Low | DPDana Park | Jul 28 | 2 |
Controlled
Sort and selection both work controlled or uncontrolled. Pass sort / onSortChange and selectedIds / onSelectionChange to lift the state; leave them off and the table manages itself (seed with defaultSort / defaultSelectedIds).
| Export to CSVORB-1390 | Done | Low | MSMateo Silva | Jun 20 | 2 | |
| Fix board drag jankORB-1419 | In review | Urgent | ARAlex Rivera | Jun 26 | 3 | |
| Ship onboarding flowORB-1428 | In progress | High | SCSam Chen | Jun 30 | 8 | |
| Redesign empty statesORB-1431 | To do | Medium | PNPriya Nair | Jul 2 | 5 | |
| Automation rules v1ORB-1402 | In progress | High | JLJordan Lee | Jul 8 | 13 | |
| Keyboard shortcuts passORB-1377 | To do | Medium | DPDana Park | Jul 11 | 5 |
sort: due asc · selected: [ORB-1428]
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| columns | DataTableColumn<T>[] | — | Column definitions — key, header, sortable, align, width, cell renderer, sortValue. |
| rows | T[] | — | Row data, one object per row. |
| getRowId | (row: T) => string | row.id | Stable row identity used for selection and React keys. |
| selectable | boolean | false | Leading 40px checkbox column with a tri-state select-all header. |
| selectedIds | string[] | — | Controlled selection. Pair with onSelectionChange. |
| defaultSelectedIds | string[] | [] | Uncontrolled initial selection. |
| onSelectionChange | (ids: string[]) => void | — | Fires with the full next selection. |
| sort | DataTableSort | null | — | Controlled sort ({ key, dir }; null = natural order). Pair with onSortChange. |
| defaultSort | DataTableSort | null | null | Uncontrolled initial sort. |
| onSortChange | (sort: DataTableSort | null) => void | — | Fires as headers cycle asc → desc → unsorted. |
| density | "default" | "compact" | "default" | Row height — 52px or 40px. The 38px header is constant. |
| stickyHeader | boolean | false | Pins header cells to the top of the scroll container. |
| toolbar | ReactNode | — | Idle toolbar content (left side). The toolbar renders when this or bulkActions is set. |
| meta | ReactNode | "N rows" | Right side of the toolbar — the row count readout. |
| bulkActions | ReactNode | (ids) => ReactNode | — | Shown next to the “N selected” count while rows are selected. |
| footer | ReactNode | — | Right side of the footer bar (e.g. pagination). The left side is an automatic selection summary. |
| rowActions | (row: T) => ReactNode | — | Trailing 44px actions column, rendered per row. |
| empty | ReactNode | — | Rendered across all columns when rows is empty. |
| containerClassName | string | — | Class for the scrollable table wrapper — e.g. a max-height for sticky headers. |
| …rest | HTMLAttributes<div> | — | Forwarded to the rounded card root. |
DataTableColumn props
Everything a column needs in one object. When cell or sortValue are omitted, the column falls back to reading row[key] directly.
| Prop | Type | Default | Description |
|---|---|---|---|
| key | string | — | Unique column id; doubles as the row field for the default cell and sort value. |
| header | ReactNode | — | Header label — rendered inside a real <button> when sortable. |
| sortable | boolean | false | Enables the three-state sort cycle and aria-sort on the header. |
| align | "left" | "right" | "left" | Right-aligned columns get 14px edge padding and a row-reversed header. |
| width | number | string | — | Fixed column width. |
| cell | (row: T) => ReactNode | — | Cell renderer — badges, avatars, glyphs, anything. |
| sortValue | (row: T) => string | number | — | Comparable value for sorting (dates as timestamps, priorities as levels…). |
| headClassName / cellClassName | string | — | Extra classes on the <th> / each <td>. |
Usage
For layouts DataTable doesn't cover, compose the styled primitives directly: Table (density, containerClassName), TableHeader, TableBody, TableRow (selected), TableHead, TableCell, TableFooter, and TableCaption. They carry the spec's metrics — 38px mono-caps header, 52/40px rows, surface-2 dividers, hover and selected tints — and everything else is plain table markup.
Right-align numbers
Tabular, right-aligned figures make columns of values easy to compare at a glance.
Pack in every field
Show the columns people scan; move the rest into a row-detail or expand.
Surface bulk actions on select
When rows are selected, replace the toolbar with the actions that apply to them.
Sort multiple columns at once
Multi-sort is hard to read; keep one active sort with a clear direction arrow.
Keyboard & accessibility
Semantic <table> / <thead> / <tbody> markup with scope=col on header cells. Sortable headers are real buttons — Tab reaches them, Enter and Space cycle the sort, and the sorted column exposes aria-sort. Checkboxes are the registry Checkbox: Space toggles a row, and the labelled header checkbox toggles all with an indeterminate middle state.
| Ship onboarding flowORB-1428 | In progress | High | SCSam Chen | Jun 30 | 8 | |
| Redesign empty statesORB-1431 | To do | Medium | PNPriya Nair | Jul 2 | 5 | |
| Fix board drag jankORB-1419 | In review | Urgent | ARAlex Rivera | Jun 26 | 3 | |
| Automation rules v1ORB-1402 | In progress | High | JLJordan Lee | Jul 8 | 13 |