DataGrid
A flexible, Vercel-style data grid component for displaying tabular data with sorting, selection, pagination, and keyboard navigation. Designed for dashboards and admin interfaces with strong accessibility support.
Usage
Basic usage
import { DataGrid } from '@nofinite/nui';
<DataGrid columns={columns} rows={rows} />;
With common interaction
<DataGrid
columns={columns}
rows={rows}
selectable
pageSize={5}
onRowClick={(row) => console.log(row)}
/>
Variants
DataGrid does not have visual variants. Customization is achieved via:
- Column alignment
- Custom cell renderers
- Row actions slot
- CSS overrides via
className
<DataGrid columns={columns} rows={rows} />
Guidelines:
- Use column
alignfor numeric or status-like data. - Use
renderfor complex cell content. - Use
renderRowActionsfor per-row controls.
Sizes
The grid adapts to its container and does not expose explicit size props.
Control sizing via:
pageSize(number of rows per page)- Container width / height
- Column
width
<DataGrid
columns={[
{ key: 'name', title: 'Name', width: 200 },
{ key: 'email', title: 'Email' },
]}
rows={rows}
pageSize={10}
/>
States
Empty state
Automatically shown when rows is empty.
<DataGrid columns={columns} rows={[]} />
Selected state
Enabled via selectable. Selected rows are visually highlighted.
<DataGrid selectable columns={columns} rows={rows} />
Focused state
- Managed internally via keyboard navigation.
- Visible focus outline when navigating with keys.
Native Props / Composition
DataGrid renders a semantic grid structure using <div> elements with ARIA roles.
Extra props can be passed via composition hooks:
<DataGrid className="my-custom-datagrid" columns={columns} rows={rows} />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | DataGridColumn[] | — | Column definitions (key, title, sorting, render, alignment) |
rows | DataRow[] | — | Data rows to render |
page | number | — | Controlled current page |
pageSize | number | 10 | Rows per page |
onPageChange | (page: number) => void | — | Page change callback |
selectable | boolean | false | Enables row selection via checkboxes |
selectedRowIds | Set<string | number> | — | Controlled selected rows |
onSelectionChange | (ids: Set<string | number>) => void | — | Selection change callback |
onRowClick | (row: DataRow) => void | — | Fired when a row is clicked |
renderRowActions | (row: DataRow) => ReactNode | — | Slot for row-level actions |
disablePagination | boolean | false | Disables pagination entirely |
className | string | "" | Additional CSS class names |
Behavior Notes
- Sorting cycles through:
ascending → descending → none. - Sorting is client-side and stable.
- Pagination is client-side.
- Selection can be controlled or uncontrolled.
- If
row.idis missing, an internal fallback ID is generated. - Clicking a row can both select it and trigger
onRowClick.
Example:
<DataGrid selectable onRowClick={(row) => console.log('Clicked:', row)} />
Accessibility
-
Uses
role="grid",row,gridcell, andcolumnheader. -
Sorting state exposed via
aria-sort. -
Row selection exposed via
aria-selected. -
Keyboard support:
ArrowUp / ArrowDown– move focusHome / End– jump to first / last rowPageUp / PageDown– change pageEnter– select row / trigger click
-
Checkboxes include descriptive
aria-labels.
Layout
- Header is sticky by default.
- Body scrolls vertically when content exceeds max height.
- Grid expands horizontally to fit columns.
- Fully responsive with adaptive cell padding.
<div style={{ maxWidth: 900 }}>
<DataGrid columns={columns} rows={rows} />
</div>
Best Practices
Do
- Provide stable
idvalues for rows. - Use
renderfor formatted or interactive cells. - Use
renderRowActionsfor contextual row actions. - Enable
selectableonly when bulk actions are needed.
Don’t
- Use
DataGridfor very small datasets where a simple list works. - Perform heavy server-side logic inside cell renderers.
- Nest complex focusable components without considering keyboard flow.
- Rely on auto-generated row IDs for persistent selection.