27.7k

Data GridNew

A full-featured data grid with sorting, selection, column resizing, pinned columns, drag-and-drop row reorder, expandable rows, virtualization, and async loading — built on the Table component.

Import

import { DataGrid } from '@darkcode-ui/react';

Usage

The DataGrid component takes a flat data array, a columns definition, and a getRowId function. It renders a fully accessible table with built-in support for sorting, selection, column resizing, and more.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Button, Chip, DataGrid, Dropdown, Label} from "@darkcode-ui/react";

Anatomy

Unlike most DarkCode UI components, DataGrid is not a compound component — it has no DataGrid.* sub-parts. Everything is configured through props and column definitions.

import { DataGrid } from '@darkcode-ui/react';

<DataGrid
  aria-label="Payments"
  columns={columns}
  data={payments}
  getRowId={(item) => item.id}
/>

Column Definitions

Columns are defined as an array of DataGridColumn<T> objects. Each column has an id, a header, and either an accessorKey (to read a value from the row object) or a custom cell renderer.

import type { DataGridColumn } from '@darkcode-ui/react';

interface Payment {
  id: string;
  customer: string;
  amount: number;
  status: 'succeeded' | 'failed';
}

const columns: DataGridColumn<Payment>[] = [
  {
    id: 'customer',
    header: 'Customer',
    accessorKey: 'customer',
    isRowHeader: true,
    allowsSorting: true,
  },
  {
    id: 'amount',
    header: 'Amount',
    accessorKey: 'amount',
    align: 'end',
    cell: (item) => `$${item.amount.toFixed(2)}`,
  },
  {
    id: 'status',
    header: 'Status',
    accessorKey: 'status',
  },
];

The cell function receives the full row item and the column definition and can return any ReactNode. The header property accepts a string, a ReactNode, or a render function that receives { sortDirection } for sortable columns.

Sorting

Mark columns as sortable with allowsSorting: true. In uncontrolled mode, the DataGrid sorts data client-side using locale-aware comparison (or a custom sortFn on the column). For server-side sorting, pass a controlled sortDescriptor and handle onSortChange.

// Uncontrolled (client-side)
<DataGrid
  defaultSortDescriptor={{ column: 'customer', direction: 'ascending' }}
  // ...
/>

// Controlled (server-side)
<DataGrid
  sortDescriptor={sortDescriptor}
  onSortChange={setSortDescriptor}
  // ...
/>

Row Selection

Enable row selection with selectionMode and showSelectionCheckboxes. Both "single" and "multiple" modes are supported, with controlled (selectedKeys + onSelectionChange) or uncontrolled (defaultSelectedKeys) state.

Pinned Columns

Pin columns to the start or end edge with pinned: "start" or pinned: "end" so they stay visible during horizontal scroll. Pinned columns must have a numeric width or minWidth. A separator appears on the boundary column whenever the pinned group detaches from the scrollable content.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Chip, DataGrid, Link} from "@darkcode-ui/react";

Drag and Drop

Enable row reorder with the onReorder callback. The DataGrid renders built-in drag handles with keyboard support (Enter to grab, arrows to move, Enter to drop) and fires the callback with the reordered data array. For advanced scenarios, pass dragAndDropHooks from React Aria's useDragAndDrop instead — it takes precedence over onReorder.

With expandable rows enabled, the built-in reorder applies to top-level rows only.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Chip, DataGrid} from "@darkcode-ui/react";

Expandable Rows

Render hierarchical data by providing a getChildren function. The DataGrid recursively renders child rows, auto-generates a chevron toggle in the treeColumn, and indents each nested level by treeIndent pixels (default 20, set 0 to disable).

The treeColumn prop specifies which column displays the chevron. If omitted, it defaults to the first isRowHeader column (or the first column). Use defaultExpandedKeys for uncontrolled expansion, or pair expandedKeys with onExpandedChange for controlled behavior. With client-side sorting, each sibling group is sorted independently.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Chip, DataGrid} from "@darkcode-ui/react";

Editable Cells

Use the cell render function to embed any interactive component — selects, number steppers, switches, text fields, and more.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Chip, DataGrid, ListBox, NumberField, Select, Switch} from "@darkcode-ui/react";

Empty State

Provide a renderEmptyState function to display a custom empty state when data is empty.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Button, DataGrid, EmptyState} from "@darkcode-ui/react";

Async Loading

Use onLoadMore, isLoadingMore, and loadMoreContent to implement infinite scroll loading. The DataGrid renders a sentinel row that triggers onLoadMore when it scrolls into view.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Chip, DataGrid, Spinner} from "@darkcode-ui/react";

Column Resizing

Enable column resizing with allowsColumnResize on the DataGrid and allowsResizing on individual columns. Columns should have minWidth set. Track widths with onColumnResize and onColumnResizeEnd.

Virtualization

Enable row virtualization for large datasets (1,000+ rows) with the virtualized prop. Only visible rows are rendered to the DOM. Set rowHeight and headingHeight to match your row content, and constrain the height via contentClassName.

"use client";

import type {DataGridColumn, DataGridSelection} from "@darkcode-ui/react";

import {Chip, DataGrid, SearchField, ToggleButton, ToggleButtonGroup} from "@darkcode-ui/react";

Bulk Actions

Combine row selection with an ActionBar to provide bulk operations like export, archive, or delete.

"use client";

import type {DataGridColumn, DataGridSelection} from "@darkcode-ui/react";

import {ActionBar, Avatar, Chip, DataGrid} from "@darkcode-ui/react";

Users

A minimal user directory using the "secondary" variant with accessorKey-only columns and a row action link — no selection, no sorting.

"use client";

import type {DataGridColumn} from "@darkcode-ui/react";

import {Button, DataGrid, Link} from "@darkcode-ui/react";

Team Members

A full-featured HR table with controlled sorting, multi-selection, pinned columns, column resizing, column visibility toggling, and search.

"use client";

import type {DataGridColumn, DataGridSelection, DataGridSortDescriptor} from "@darkcode-ui/react";

import {Avatar, Button, Chip, DataGrid, Dropdown, Label, SearchField} from "@darkcode-ui/react";

Servers

A server monitoring dashboard with controlled sorting, selection, search, and rich cell renderers including sparkline charts and circular progress indicators.

"use client";

import type {DataGridColumn, DataGridSelection, DataGridSortDescriptor} from "@darkcode-ui/react";

import {Button, Chip, DataGrid, ProgressCircle, SearchField} from "@darkcode-ui/react";

Styling

CSS Classes

  • .data-grid — Root wrapper. Defines the --data-grid-* custom properties.
  • .data-grid__selection-column / .data-grid__selection-cell — Narrow column for the select-all and row checkboxes. Width from --data-grid-selection-column-width.
  • .data-grid__drag-handle-column / .data-grid__drag-handle-cell — Narrow column for the drag handles. Width from --data-grid-drag-handle-column-width.
  • .data-grid__drag-handle — The grip button inside each row. cursor: grab, grabbing while pressed.
  • .data-grid__sort-icon — Chevron next to sortable column headers. Rotates 180° when descending.
  • .data-grid__empty-state — Centered container for the empty state message.
  • .data-grid__tree-cell — Flex wrapper inside the treeColumn cell holding the chevron toggle and cell content. Per-level indentation via --data-grid-tree-indent.
  • .data-grid__tree-toggle / .data-grid__tree-toggle-icon — Expand/collapse chevron button and icon. The icon rotates 90° when expanded via [data-expanded].
  • .data-grid__tree-toggle-spacer — Invisible placeholder for leaf rows so content aligns with siblings that have a chevron.

Data Attributes

  • [data-align="center" | "end"] — Set on header and body cells from the column align option.
  • [data-vertical-align="top" | "middle" | "bottom"] — Set on the root from the verticalAlign prop.
  • [data-pinned="start" | "end"] — Sticky pinned cells.
  • [data-pinned-edge] — Boundary column of a pinned group; shows the separator.
  • [data-pinned-start-detached] / [data-pinned-end-detached] — Set on the root while the content is scrolled away from the pinned edge.

CSS Variables

  • --data-grid-selection-column-width — Width of the selection checkbox column (default 40px).
  • --data-grid-drag-handle-column-width — Width of the drag handle column (default 32px).
  • --data-grid-tree-toggle-size — Size of the expand/collapse chevron button and its leaf-row spacer (default 24px).
  • --data-grid-tree-gap — Gap between the chevron/spacer and the cell content (default 4px).
  • --data-grid-tree-indent — Indentation per nested level (default 20px, set from the treeIndent prop).

API Reference

DataGrid

Accepts a generic type parameter T for the row data shape.

PropTypeDefaultDescription
dataT[]-Row data array
columnsDataGridColumn<T>[]-Column definitions
getRowId(item: T) => Key-Extracts a unique key from each row item
aria-labelstring-Accessible label for the table. Required
variant'primary' | 'secondary''primary'Visual variant passed to the underlying Table
classNamestring-Additional className for the root wrapper
contentClassNamestring-Additional className for the inner <table> element
scrollContainerClassNamestring-Additional className for the scroll container
verticalAlign'top' | 'middle' | 'bottom''middle'Vertical alignment of cell content
selectionMode'none' | 'single' | 'multiple''none'Row selection mode
selectedKeysDataGridSelection-Controlled selected row keys
defaultSelectedKeysDataGridSelection-Default selected row keys (uncontrolled)
onSelectionChange(keys: DataGridSelection) => void-Callback when selection changes
selectionBehavior'toggle' | 'replace''toggle'Selection interaction model
showSelectionCheckboxesbooleanfalseAuto-prepend a checkbox column for selection
disabledKeysIterable<Key>-Keys of rows that should be disabled
sortDescriptorDataGridSortDescriptor-Controlled sort descriptor
defaultSortDescriptorDataGridSortDescriptor-Default sort descriptor (uncontrolled client-side sorting)
onSortChange(descriptor: DataGridSortDescriptor) => void-Callback when sort changes. Fires in both modes
allowsColumnResizebooleanfalseEnable column resizing on columns that opt in
onColumnResize(widths: Map<Key, DataGridColumnSize>) => void-Callback during column resize
onColumnResizeEnd(widths: Map<Key, DataGridColumnSize>) => void-Callback when resize ends
onReorder(event: DataGridReorderEvent<T>) => void-Enables built-in drag-and-drop row reorder
dragAndDropHooksDataGridDragAndDropHooks-Advanced React Aria drag-and-drop hooks. Overrides onReorder
onRowAction(key: Key) => void-Callback when a row is actioned
renderEmptyState() => ReactNode-Render function for the empty state
onLoadMore() => void-Callback when the load-more sentinel scrolls into view
isLoadingMorebooleanfalseWhether more data is currently being fetched
loadMoreContentReactNode-Content inside the load-more sentinel row
virtualizedbooleanfalseEnable row virtualization for large datasets
rowHeightnumber42Fixed row height in pixels (virtualized mode)
headingHeightnumber36Header row height in pixels (virtualized mode)
getChildren(item: T) => T[] | undefined-Return child rows. Enables expandable/tree rows
treeColumnstring-Column id that displays the expand/collapse chevron
expandedKeysDataGridSelection-Controlled set of expanded row keys
defaultExpandedKeysDataGridSelection-Default expanded row keys (uncontrolled)
onExpandedChange(keys: DataGridSelection) => void-Callback when expanded rows change
treeIndentnumber20Pixels of indentation per nested level. 0 disables

DataGridColumn

Column definition object passed to the columns prop.

PropertyTypeDefaultDescription
idstring-Unique column identifier. Used as the sort key. Required
headerReactNode | (info) => ReactNode-Header content. Render function receives { sortDirection }
accessorKeykeyof T & string-Key on T to read the cell value from
cell(item: T, column) => ReactNode-Custom cell renderer
isRowHeaderbooleanfalseMark this column as the row header (for accessibility)
allowsSortingbooleanfalseAllow this column to be sorted
sortFn(a: T, b: T) => number-Custom sort comparator
allowsResizingboolean-Allow resizing (with allowsColumnResize on the grid)
widthDataGridColumnSize-Initial column width (px, %, or fr)
minWidthnumber-Minimum column width
maxWidthnumber-Maximum column width
align'start' | 'center' | 'end''start'Cell text alignment
headerClassNamestring-Additional className for every <th> of this column
cellClassNamestring-Additional className for every <td> of this column
pinned'start' | 'end'-Pin this column. Requires numeric width or minWidth

DataGridReorderEvent

Event object passed to the onReorder callback.

PropertyTypeDescription
keysSet<Key>The keys that were moved
target{ key: Key; dropPosition: 'before' | 'after' }The target row key and drop position
reorderedDataT[]The full reordered data array after applying the move

Type Exports

TypeDescription
DataGridSelectionA set of selected keys, or 'all'
DataGridSortDescriptorThe current sort column and direction
DataGridSortDirection'ascending' | 'descending'
DataGridColumnSizeA number, numeric string, percentage, or fractional unit
DataGridDragAndDropHooksHooks returned by React Aria's useDragAndDrop

On this page