Skip to main content

DataGrid

A feature-rich tabular data component designed for structured data presentation with built-in sorting, pagination, row selection, keyboard navigation, custom cell rendering, and action slots.

Supports both controlled and uncontrolled modes for pagination and selection while preserving accessibility semantics via ARIA grid roles.


Usage

Basic DataGrid

import { DataGrid } from '@nofinite/nui';

<DataGrid
columns={[
{ key: 'name', title: 'Name' },
{ key: 'email', title: 'Email' },
{ key: 'role', title: 'Role' },
]}
rows={users}
/>;

Sortable Columns

<DataGrid
columns={[
{ key: 'name', title: 'Name', sortable: true },
{ key: 'salary', title: 'Salary', sortable: true },
]}
rows={employees}
/>

Custom Cell Rendering

<DataGrid
columns={[
{ key: 'name', title: 'Name' },
{
key: 'status',
title: 'Status',
render: (row) => <Badge>{row.status}</Badge>,
},
]}
rows={data}
/>

Row Selection

<DataGrid selectable rows={data} columns={columns} />

Pagination Control

<DataGrid
page={page}
onPageChange={setPage}
pageSize={20}
rows={data}
columns={columns}
/>

Row Actions

<DataGrid
rows={data}
columns={columns}
renderRowActions={(row) => (
<>
<Button onClick={() => edit(row)}>Edit</Button>
<Button variant="danger" onClick={() => remove(row)}>
Delete
</Button>
</>
)}
/>

Props

PropTypeDefaultDescription
columnsDataGridColumn<T>[]Column definitions
rowsT[]Dataset
pagenumberinternalControlled page
pageSizenumber10Rows per page
onPageChange(page:number)=>voidPage callback
selectablebooleanfalseEnables checkbox selection
selectedRowIdsSet<string | number>internalControlled selection
onSelectionChange(ids:Set)=>voidSelection callback
onRowClick(row:T)=>voidRow click handler
renderRowActions(row:T)=>ReactNodeAction slot
classNamestringCustom styles
disablePaginationbooleanfalseTurns off pagination

Column Definition

FieldTypeDescription
keykeyof TData field
titleReactNodeHeader label
sortablebooleanEnables sorting
widthstring | numberColumn width
align'left' | 'center' | 'right'Cell alignment
render(row:T)=>ReactNodeCustom cell
sortFn(a,b)=>numberCustom comparator

Variants

<DataGrid rows={data} columns={columns} />                     // Default
<DataGrid selectable rows={data} columns={columns} /> // Selectable
<DataGrid disablePagination rows={data} columns={columns} /> // Static grid
<DataGrid renderRowActions={actions} rows={data} columns={columns} /> // Action grid

Available variants

  • default — Standard tabular data
  • selectable — Checkbox-based selection
  • action — Row-level actions column
  • static — Pagination disabled
  • interactive — Row click enabled

Guidelines

  • Use selectable for bulk operations
  • Use action when row-specific commands exist
  • Use static for small datasets
  • Use interactive when rows act as navigation targets

States

StateDescription
idleDefault rendering
sortedColumn sorting active
selectedRow selected
focusedKeyboard navigated row
emptyNo dataset
paginatedMultiple pages

Keyboard Interaction

KeyBehavior
ArrowDownMove focus to next row
ArrowUpMove focus to previous row
Enter / SpaceSelect row or trigger click

Accessibility

  • Implements ARIA grid pattern
  • aria-rowcount for dataset size
  • aria-selected for selected rows
  • Header sorting announced via aria-sort
  • Focusable wrapper enabling keyboard navigation
  • Checkbox selection accessible via labels

Design Tokens

:root {
--nui-radius-lg: 12px;
--nui-radius-md: 8px;
--nui-space-3: 12px;
--nui-space-4: 16px;

--nui-bg-surface: #ffffff;
--nui-bg-subtle: #f9fafb;
--nui-border-default: #e5e7eb;
--nui-fg-default: #111827;
--nui-fg-muted: #6b7280;
}

Best Practices

Do

  • Provide stable row IDs for predictable selection
  • Use custom sortFn for complex data types
  • Keep column count manageable for readability
  • Use pagination for large datasets
  • Add row actions for contextual workflows

Don’t

  • Mix row navigation and destructive actions without visual distinction
  • Overuse sortable columns causing cognitive overload
  • Disable pagination for extremely large datasets
  • Depend solely on hover for action visibility
  • Render expensive components inside large grids without memoization