Data Grid
Preview: Default
Data grid: TanStack Table v9 for search, sorting, pagination and column visibility, rendered with the React Aria Table for grid keyboard navigation and selection.
Import
import { DataGrid, DataGridCheckbox } from '@marbleui/ui'Props
<DataGrid>
| Prop | Type | Default | Description |
|---|---|---|---|
| aria-label *required | string | — | |
| columns *required | DataGridColumn<T>[] | — | |
| data *required | T[] | — | |
| className | string | — | |
| density | 'compact' | 'regular' | 'regular' | |
| emptyText | string | 'No results' | |
| onSelectionChange | (keys: Selection) => void | — | |
| pageSize | number | 10 | |
| searchable | boolean | true | |
| selectionMode | 'single' | 'none' | 'multiple' | 'multiple' | |
| striped | boolean | — | |
| toolbar | ReactNode | — | Extra controls in the toolbar (e.g. a FilterBar, bulk actions). |
<DataGridCheckbox>alias of Checkbox
Checkbox with label and description; supports indeterminate, groups and a card style.
| Prop | Type | Default | Description |
|---|---|---|---|
| description | ReactNode | — | |
| variant | 'default' | 'card' | — |
Also accepts React Aria props (111).
Usage notes
Full data table: search, sorting, pagination, column visibility and row selection (TanStack Table v9 rendered with React Aria Table, so it’s a proper keyboard grid).
const columns: DataGridColumn<Order>[] = [
{ id: 'id', header: 'Order', isRowHeader: true, value: (o) => o.id },
{ id: 'amount', header: 'Amount', align: 'end', sortable: true, value: (o) => o.amount, cell: (o) => money(o.amount) },
]
<DataGrid aria-label="Orders" data={orders} columns={columns} pageSize={10} />
valuedrives sorting and search;cellonly renders. Keep them consistent.- Mark one column
isRowHeaderso screen readers announce rows by it. - Every row needs a stable
id. Usetoolbarfor filters and bulk actions;selectionMode="none"for read-only tables. - For a plain table without search/pagination use
Table.
Example source · show· hide
import { Avatar } from '../avatar'
import { Badge } from '../badge'
import { DataGrid, type DataGridColumn } from './data-grid'
type User = { id: number; name: string; email: string; role: 'Owner' | 'Admin' | 'Member' | 'Guest'; status: 'Active' | 'Invited' | 'Suspended'; seats: number; joined: Date }
const first = ['Maya', 'Charles', 'Ada', 'Grace', 'Alan', 'Katherine', 'Linus', 'Margaret', 'Tim', 'Barbara', 'Dennis', 'Radia']
const last = ['Chen', 'Webb', 'Lovelace', 'Hopper', 'Turing', 'Johnson', 'Torvalds', 'Hamilton', 'Berners-Lee', 'Liskov', 'Ritchie', 'Perlman']
const roles = ['Owner', 'Admin', 'Member', 'Member', 'Guest'] as const
const statuses = ['Active', 'Active', 'Active', 'Invited', 'Suspended'] as const
const users: User[] = Array.from({ length: 48 }, (_, i) => {
const name = `${first[i % 12]} ${last[(i * 5) % 12]}`
return {
id: i + 1,
name,
email: `${name.split(' ')[0]!.toLowerCase()}.${i}@acme.com`,
role: roles[i % 5]!,
status: statuses[(i * 3) % 5]!,
seats: ((i * 7) % 12) + 1,
joined: new Date(2025, (i * 3) % 12, ((i * 11) % 27) + 1),
}
})
const tone = { Active: 'success', Invited: 'accent', Suspended: 'danger' } as const
const dateFmt = new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', year: 'numeric' })
const columns: DataGridColumn<User>[] = [
{ id: 'name', header: 'Name', isRowHeader: true, sortable: true, hideable: false, value: (u) => u.name, cell: (u) => (
<span className="flex items-center gap-2.5"><Avatar size="xs" name={u.name} /><span className="flex flex-col"><span className="font-medium">{u.name}</span><span className="text-xs text-fg-muted">{u.email}</span></span></span>
) },
{ id: 'role', header: 'Role', sortable: true, value: (u) => u.role },
{ id: 'status', header: 'Status', sortable: true, value: (u) => u.status, cell: (u) => <Badge tone={tone[u.status]} dot>{u.status}</Badge> },
{ id: 'seats', header: 'Seats', sortable: true, align: 'end', value: (u) => u.seats },
{ id: 'joined', header: 'Joined', sortable: true, value: (u) => u.joined, cell: (u) => <span className="text-fg-muted">{dateFmt.format(u.joined)}</span> },
]
export const styles = {
Default: () => <DataGrid aria-label="Members" data={users} columns={columns} pageSize={8} className="w-[46rem]" />,
Compact: () => <DataGrid aria-label="Members" data={users} columns={columns} pageSize={12} density="compact" striped selectionMode="none" className="w-[46rem]" />,
}Source: packages/ui/src/data-grid/data-grid.tsx
Catalog
- Category
- data-grid
- Priority
- Pro
- Primitive
- composed
- React Aria
- Table + Virtualizer