Data Grid
Sorting and selection over Table, driven by a column definition. The sort is stable and never mutates your array, so re-sorting on an equal column leaves settled rows where they were.
src/components/ui/data-grid.tsxAbout
From the component's own source, where it was written.
A sortable, selectable table driven by a column definition.
Table stays the presentational layer; this adds the behaviour that every table grows eventually and that everyone re-implements slightly differently.
Sorting is stable and non-destructive: rows are indexed, compared, and the original order breaks ties, so re-sorting on an equal column never shuffles rows that looked settled. Sorting also never mutates the caller's array.
Install
npx astralyx-ui add data-grid
Usage
import { DataGrid, type DataGridColumn } from '@/components/ui/data-grid'
const columns: DataGridColumn<Row>[] = [
{ key: 'id', header: '#', sortable: true },
{ key: 'status', header: 'Status', render: (row) => <Badge>{row.status}</Badge> },
]
<DataGrid columns={columns} rows={rows} rowKey={(row) => row.id} selectable />Composer
Change the props and the source below follows.
| 1482 | main | passed | |
| 1481 | feat/toast | passed | |
| 1480 | main | failed | |
| 1479 | fix/input | passed |
<DataGrid
columns={columns}
rows={rows}
rowKey={(row) => row.id}
selectable={true}
/>Examples
Builds
<DataGrid
columns={columns}
rows={rows}
rowKey={(row) => row.id}
selectable
defaultSort={{ key: 'id', direction: 'desc' }}
/>API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
DataGrid<Row extends Record<string, unknown>>
Extends Omit<ComponentProps<'div'>, 'onSelect'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| columns | Column<Row>[] | required | { key, header, render?, sortValue?, sortable?, align?, hideOnMobile?, width? }. |
| rows | Row[] | required | — |
| rowKey | (row: Row) => string | required | Stable identity, used for React keys and for selection. |
| defaultSort | SortState | null | Initial sort. Clicking a header cycles ascending, descending, off. |
| selectable | boolean | false | Header checkbox selects the page and goes indeterminate on a partial selection. |
| selected | string[] | — | Header checkbox selects the page and goes indeterminate on a partial selection. |
| onSelectedChange | (ids: string[]) => void | — | Header checkbox selects the page and goes indeterminate on a partial selection. |
| onRowClick | (row: Row) => void | — | — |
| empty | ReactNode | — | — |
| emptyLabel | string | 'No rows' | Tooltip on the empty state. |
Types
Column<Row> = DataGridColumn
A sortable, selectable table driven by a column definition.
| Field | Type | Description |
|---|---|---|
| key | string | — |
| header | ReactNode | — |
| render? | (row: Row) => ReactNode | Cell contents. Defaults to row[key]. |
| sortValue? | (row: Row) => string | number | For anything not directly comparable — a formatted date, a status rank. |
| sortable? | boolean | — |
| align? | 'start' | 'end' | 'center' | — |
| hideOnMobile? | boolean | Drops the column below sm instead of letting the table scroll sideways for a nice-to-have field. |
| width? | string | — |