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.tsx

About

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.

1482mainpassed
1481feat/toastpassed
1480mainfailed
1479fix/inputpassed
Props
tsx
<DataGrid
  columns={columns}
  rows={rows}
  rowKey={(row) => row.id}
  selectable={true}
/>

Examples

Builds

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'>.

PropTypeDefaultDescription
columnsColumn<Row>[]required{ key, header, render?, sortValue?, sortable?, align?, hideOnMobile?, width? }.
rowsRow[]required—
rowKey(row: Row) => stringrequiredStable identity, used for React keys and for selection.
defaultSortSortStatenullInitial sort. Clicking a header cycles ascending, descending, off.
selectablebooleanfalseHeader checkbox selects the page and goes indeterminate on a partial selection.
selectedstring[]—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——
emptyReactNode——
emptyLabelstring'No rows'Tooltip on the empty state.

Types

Column<Row> = DataGridColumn

A sortable, selectable table driven by a column definition.

FieldTypeDescription
keystring—
headerReactNode—
render?(row: Row) => ReactNodeCell contents. Defaults to row[key].
sortValue?(row: Row) => string | numberFor anything not directly comparable — a formatted date, a status rank.
sortable?boolean—
align?'start' | 'end' | 'center'—
hideOnMobile?booleanDrops the column below sm instead of letting the table scroll sideways for a nice-to-have field.
width?string—