Table
A bounded grid with a pinned header and sortable columns
| auth-service | production | ready | 74s | ||
| billing-api | production | ready | 92s | ||
| edge-gateway | production | failed | 36s | ||
| media-proxy | development | building | 129s | ||
| reports-worker | staging | ready | 211s |
Chosen and sorted
| Duration | Service |
|---|---|
| 211s | reports-worker |
| 148s | search-index |
| 129s | media-proxy |
Two sorts
| Environment | Service |
|---|---|
| development | media-proxy |
| production | edge-gateway |
| production | billing-api |
| production | auth-service |
Empty
| Service | Status |
|---|---|
No deploy matches “eu-west”. | |
Loading
| Service | Duration |
|---|---|
Installation
npx shadcn@latest add @sudokw/data-tableimport { Table } from "@gpuixui/data";Usage
import {
Table,
TableBody,
TableCell,
TableHeader,
TableHeaderCell,
TableRow,
TableViewport,
useColumns,
useTable,
} from "@gpuixui/data";
const columns = useColumns({
columns: [
{ id: "service", label: "Service", width: 260 },
{ id: "environment", label: "Environment", width: 140 },
],
});
const table = useTable({
rows,
keyOf: (row) => row.id,
columns: [
{ id: "service", valueOf: (row) => row.service },
{ id: "environment", valueOf: (row) => row.environment },
],
hiddenColumns: columns.hidden,
});
<Table aria-label="Deploy queue" height={320}>
<TableViewport>
<TableHeader>
<TableRow>
<TableHeaderCell width={260}>Service</TableHeaderCell>
<TableHeaderCell width={140}>Environment</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
{table.rows.map((row) => (
<TableRow
key={row.id}
onClick={(event) => table.press(row.id, event.modifiers)}
selected={table.isSelected(row.id)}
>
<TableCell width={260}>{row.service}</TableCell>
<TableCell width={140}>{row.environment}</TableCell>
</TableRow>
))}
</TableBody>
</TableViewport>
</Table>;Composition
Table
└── TableViewport
├── TableHeader
│ └── TableHeaderCell
├── TableBody
│ └── TableRow
│ └── TableCell
├── TableCaption
├── TableEmpty
└── TableSkeletonAPI reference
Table
| Prop | Type | Default |
|---|---|---|
height | number — a definite height; the header stays painted and the body scrolls | — |
children | ReactNode — a TableHeader, an optional TableSkeleton, one TableBody | — |
className | string — joined after the recipe, so it wins conflicts | — |
TableViewport, TableHeader, TableBody
| Prop | Type | Default |
|---|---|---|
rows | number — the skeleton's row count when the body has no children | 3 |
height | number — the body height Table measures and hands down | measured |
children | ReactNode — the rows, or the header cells the part owns | — |
className | string | — |
TableRow
| Prop | Type | Default |
|---|---|---|
selected | boolean — the chosen record's wash and label role | false |
disabled | boolean — no press, no pointer cursor | false |
instanceRef | Ref<PublicInstance> — the painted element, for renderer.focusElement | — |
children | ReactNode — the row's cells | — |
className | string | — |
TableHeaderCell, TableCell
| Prop | Type | Default |
|---|---|---|
width | number — a fixed track; omitted, the cell shares the leftover width | — |
align | "left" | "center" | "right" | "left" |
children | ReactNode — the cell's text or element | — |
className | string | — |
TableSkeleton
| Prop | Type | Default |
|---|---|---|
rows | number — bars, one row each | 3 |
columns | number — bars per row | 3 |
TableSortHeader
| Prop | Type | Default |
|---|---|---|
field | string — the field a press reports | — |
label | string — the visible label and the base of the accessible name | — |
sort | Option<SortState> — the primary sort, for a single-sort consumer | — |
order | SortOrder — the whole order, primary first | sort alone |
initialDirection | "asc" | "desc" — the direction a first press starts at | "asc" |
onSort | (next: SortState) => void — the single-column contract | — |
onSortPress | (field, initialDirection, modifiers) => void — the raw press, so the controller can compose an order | — |
width | number — a fixed track | — |
align | "left" | "center" | "right" | "left" |
resize | TableColumnResizeProps — the divider; needs a fixed width | — |
testId | string | — |
The sort surface useTable exposes
| Member | Type | Consequence |
|---|---|---|
sort | Option<SortState> | the primary entry, for a single-sort readout or header |
sortOrder | SortOrder | every sorted field, primary first — what the rows and the header read |
setSort | (sort: Option<SortState>) => void | replace the order with one entry, or none |
toggleSort | (field: string, additive?: boolean) => void | the press cycle; additive keeps the order and adds a tie-break |
pressSort | (field, initialDirection, modifiers?) => void | the raw press; modifiers.shift is what sets additive |
rows | ReadonlyArray<Row> | filtered by the query, then ordered by every entry in turn |
Edit this page on GitHubapps/docs/content/docs/components/table.mdx