The DataGrid component is designed to handle large datasets efficiently while offering a rich set of features for customization and interactivity.
- React 19.2+ support
- Evergreen browsers and server-side rendering support
- Tree-shaking support with no external dependencies to keep your bundles slim
- Great performance thanks to virtualization: columns and rows outside the viewport are not rendered
- Strictly typed with TypeScript
- Keyboard accessibility
- Light and dark mode support out of the box via
color-scheme - Frozen columns: Freeze columns to keep them visible during horizontal scrolling.
- Column resizing
- Multi-column sorting
- Click on a sortable column header to toggle between its ascending/descending sort order
- Ctrl+Click / Meta+Click to sort an additional column
- Column spanning
- Column grouping
- Row selection
- Row grouping
- Summary rows
- Dynamic row heights
- No rows fallback
- Cell formatting
- Cell editing
- Cell copying / pasting
- Cell value dragging / filling
- Customizable renderers
- Right-to-left (RTL) support
Install react-data-grid using your favorite package manager:
# npm
npm install react-data-grid
# Vite+
vp add react-data-grid
# pnpm
pnpm add react-data-grid
# Yarn
yarn add react-data-grid
# Bun
bun add react-data-gridAdditionally, import the default styles in your application:
import 'react-data-grid/lib/styles.css';react-data-grid is published as ECMAScript modules for evergreen browsers, bundlers, and server-side rendering.
Important
Vite 8+ uses Lightning CSS by default to minify CSS, and Lightning CSS has a bug minifying thelight-dark()syntax. You can tweak thecssMinifyorcssTargetsettings as a workaround.
build: {
cssMinify: 'esbuild', // requires the `esbuild` package to be installed
// or
cssTarget: 'esnext'
}Here is a basic example of how to use react-data-grid in your React application:
import 'react-data-grid/lib/styles.css';
import { DataGrid, type Column } from 'react-data-grid';
interface Row {
id: number;
title: string;
}
const columns: readonly Column<Row>[] = [
{ key: 'id', name: 'ID' },
{ key: 'title', name: 'Title' }
];
const rows: readonly Row[] = [
{ id: 0, title: 'Example' },
{ id: 1, title: 'Demo' }
];
function App() {
return <DataGrid columns={columns} rows={rows} />;
}The DataGrid provides multiple ways to customize its appearance and behavior.
The DataGrid supports both light and dark color schemes out of the box using the light-dark() CSS function. The theme automatically adapts based on the user's system preference when color-scheme: light dark; is set.
To enforce a specific theme, we recommend setting the standard color-scheme CSS property on the :root:
:root {
color-scheme: light; /* or 'dark', or 'light dark' for auto */
}Alternatively, you can add the rdg-light or rdg-dark class to individual grids:
// Force light theme
<DataGrid className="rdg-light" columns={columns} rows={rows} />
// Force dark theme
<DataGrid className="rdg-dark" columns={columns} rows={rows} />The DataGrid supports the following CSS variables for customization:
.rdg {
/* Selection */
--rdg-selection-width: 2px;
--rdg-selection-color: hsl(207, 75%, 66%);
/* Typography */
--rdg-font-size: 14px;
/* Colors (using light-dark() for automatic theme switching) */
--rdg-color: light-dark(#000, #ddd);
--rdg-background-color: light-dark(hsl(0deg 0% 100%), hsl(0deg 0% 13%));
/* Header */
--rdg-header-background-color: light-dark(hsl(0deg 0% 97.5%), hsl(0deg 0% 10.5%));
--rdg-header-draggable-background-color: light-dark(hsl(0deg 0% 90.5%), hsl(0deg 0% 17.5%));
/* Rows */
--rdg-row-hover-background-color: light-dark(hsl(0deg 0% 96%), hsl(0deg 0% 9%));
--rdg-row-selected-background-color: light-dark(hsl(207deg 76% 92%), hsl(207deg 76% 42%));
--rdg-row-selected-hover-background-color: light-dark(hsl(207deg 76% 88%), hsl(207deg 76% 38%));
/* Borders */
--rdg-border-width: 1px;
--rdg-border-color: light-dark(#ddd, #444);
--rdg-summary-border-width: calc(var(--rdg-border-width) * 2);
--rdg-summary-border-color: light-dark(#aaa, #555);
/* Checkboxes */
--rdg-checkbox-focus-color: hsl(207deg 100% 69%);
/* Frozen columns */
--rdg-frozen-column-shadow-color: light-dark(rgb(0 0 0 / 15%), rgb(0 0 0 / 40%));
}Example of customizing colors:
.my-custom-grid {
--rdg-background-color: #f0f0f0;
--rdg-selection-color: #ff6b6b;
--rdg-font-size: 16px;
}<DataGrid className="my-custom-grid" columns={columns} rows={rows} />The DataGrid accepts standard className and style props:
<DataGrid
columns={columns}
rows={rows}
className="my-grid custom-theme"
style={{ width: 800, height: 600 }}
/>Control row heights using the rowHeight, headerRowHeight, and summaryRowHeight props. The rowHeight prop supports both fixed heights and dynamic heights per row.
Apply custom CSS classes to rows using the rowClass prop, and to header rows using the headerRowClass prop.
Apply custom CSS classes to cells using the cellClass property in column definitions. You can also use headerCellClass and summaryCellClass for header and summary cells, respectively.
Control column widths using the width, minWidth, and maxWidth properties in column definitions. Enable column resizing using the resizable property, or use defaultColumnOptions to apply it to all columns.
Replace default components with custom implementations using the renderers prop. Columns can also have custom renderers using the renderCell, renderHeaderCell, renderSummaryCell, renderGroupCell, and renderEditCell properties.
An array of column definitions and/or column groups. See the ColumnOrColumnGroup type for all available options.
columns array will trigger a re-render and recalculation for the entire grid. Always memoize this prop using useMemo or define it outside the component to avoid unnecessary re-renders.
An array of rows. The row data can be of any type.
💡 Performance: The grid is optimized for efficient rendering:
-
Virtualization: Only visible rows are rendered in the DOM
-
Individual row updates: Row components are memoized, so updating a single row object will only re-render that specific row, not all rows
-
Array reference matters: Changing the array reference itself (e.g.,
setRows([...rows])) triggers viewport and layout recalculations, even if the row objects are unchanged -
Best practice: When updating rows, create a new array but reuse unchanged row objects. For example:
// ✅ Good: Only the changed row is re-rendered setRows(rows.map((row, idx) => (idx === targetIdx ? { ...row, updated: true } : row))); // ❌ Avoid: Creates new references for all rows, causing all visible rows to re-render setRows(rows.map((row) => ({ ...row })));
Optional ref for imperative APIs like scrolling to or focusing a cell. See DataGridHandle.
Rows pinned at the top of the grid for summary purposes.
Rows pinned at the bottom of the grid for summary purposes.
Function to return a unique key/identifier for each row. rowKeyGetter is required for row selection to work.
import { DataGrid } from 'react-data-grid';
interface Row {
id: number;
name: string;
}
function rowKeyGetter(row: Row) {
return row.id;
}
function MyGrid() {
return <DataGrid columns={columns} rows={rows} rowKeyGetter={rowKeyGetter} />;
}💡 While optional, setting this prop is recommended for optimal performance, as the returned value is used to set the key prop on the row elements.
useCallback to prevent unnecessary re-renders.
Callback triggered when rows are changed.
The first parameter is a new rows array with both the updated rows and the other untouched rows.
The second parameter is an object with an indexes array highlighting which rows have changed by their index, and the column where the change happened. See the RowsChangeData type.
import { useState } from 'react';
import { DataGrid } from 'react-data-grid';
function MyGrid() {
const [rows, setRows] = useState(initialRows);
return <DataGrid columns={columns} rows={rows} onRowsChange={setRows} />;
}Default: 35 pixels
Height of each row in pixels. A function can be used to set different row heights.
// Fixed height for all rows
<DataGrid columns={columns} rows={rows} rowHeight={50} />;
// Dynamic height per row
function getRowHeight(row) {
return row.isExpanded ? 100 : 35;
}
<DataGrid columns={columns} rows={rows} rowHeight={getRowHeight} />;rowHeight function.
Default: rowHeight when it is a number, otherwise 35 pixels
Height of the header row in pixels.
Default: rowHeight when it is a number, otherwise 35 pixels
Height of each summary row in pixels.
<DataGrid
columns={columns}
rows={rows}
rowHeight={35}
headerRowHeight={45}
summaryRowHeight={40}
topSummaryRows={topSummaryRows}
/>A map of column widths containing both measured and resized widths. If not provided, an internal state is used. See the ColumnWidths type.
const [columnWidths, setColumnWidths] = useState((): ColumnWidths => new Map());
function addNewRow() {
setRows(...);
// reset column widths after adding a new row
setColumnWidths(new Map());
}
return <DataGrid columnWidths={columnWidths} onColumnWidthsChange={setColumnWidths} ... />Callback triggered when column widths change. If not provided, an internal state is used. See the ColumnWidths type.
A set of selected row keys. rowKeyGetter is required for row selection to work.
Function to determine if row selection is disabled for a specific row.
Callback triggered when the selection changes.
import { useState } from 'react';
import { DataGrid, SelectColumn, type Column } from 'react-data-grid';
const rows: readonly Row[] = [...];
const columns: readonly Column<Row>[] = [
SelectColumn,
// other columns
];
function rowKeyGetter(row: Row) {
return row.id;
}
function isRowSelectionDisabled(row: Row) {
return !row.isActive;
}
function MyGrid() {
const [selectedRows, setSelectedRows] = useState((): ReadonlySet<number> => new Set());
return (
<DataGrid
rowKeyGetter={rowKeyGetter}
columns={columns}
rows={rows}
selectedRows={selectedRows}
isRowSelectionDisabled={isRowSelectionDisabled}
onSelectedRowsChange={setSelectedRows}
/>
);
}An array of sorted columns. See the SortColumn type.
Sorting is controlled: the grid does not reorder rows for you. Apply the sorting to your rows state (or derived rows) based on sortColumns.
Callback triggered when sorting changes.
import { useState } from 'react';
import { DataGrid, type Column, type SortColumn } from 'react-data-grid';
const rows: readonly Row[] = [...];
const columns: readonly Column<Row>[] = [
{
key: 'name',
name: 'Name',
sortable: true
},
// other columns
];
function MyGrid() {
const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([]);
return (
<DataGrid
columns={columns}
rows={rows}
sortColumns={sortColumns}
onSortColumnsChange={setSortColumns}
/>
);
}More than one column can be sorted via Ctrl+Click (Cmd+Click on macOS). To disable multi-column sorting, change the onSortColumnsChange function to:
function onSortColumnsChange(sortColumns: SortColumn[]) {
setSortColumns(sortColumns.slice(-1));
}Default options applied to all columns. See the DefaultColumnOptions type.
function MyGrid() {
return (
<DataGrid
columns={columns}
rows={rows}
defaultColumnOptions={{
minWidth: 100,
resizable: true,
sortable: true,
draggable: true
}}
/>
);
}Callback triggered when a pointer becomes active in a cell. The default behavior is to focus the cell. Call preventGridDefault to prevent the default behavior. See the CellMouseArgs and CellMouseEvent types.
function onCellMouseDown(args: CellMouseArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
event.preventGridDefault();
}
}
<DataGrid rows={rows} columns={columns} onCellMouseDown={onCellMouseDown} />;Callback triggered when a cell is clicked. See the CellMouseArgs and CellMouseEvent types.
This event can be used to open the cell editor on a single click:
function onCellClick(args: CellMouseArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
args.setActivePosition(true);
}
}
<DataGrid rows={rows} columns={columns} onCellClick={onCellClick} />;Callback triggered when a cell is double-clicked. The default behavior is to open the editor if the cell is editable. Call preventGridDefault to prevent the default behavior. See the CellMouseArgs and CellMouseEvent types.
function onCellDoubleClick(args: CellMouseArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
event.preventGridDefault();
}
}
<DataGrid rows={rows} columns={columns} onCellDoubleClick={onCellDoubleClick} />;Callback triggered when a cell is right-clicked. See the CellMouseArgs and CellMouseEvent types.
function onCellContextMenu(args: CellMouseArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
event.preventDefault();
// open custom context menu
}
}
<DataGrid rows={rows} columns={columns} onCellContextMenu={onCellContextMenu} />;Callback triggered when a key is pressed in a cell. This event can be used to customize cell navigation and editing behavior. See the CellKeyDownArgs and CellKeyboardEvent types.
Examples
- Prevent editing on
Enter
function onCellKeyDown(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) {
if (args.mode === 'ACTIVE' && event.key === 'Enter') {
event.preventGridDefault();
}
}- Prevent navigation on
Tab
function onCellKeyDown(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) {
if (args.mode === 'ACTIVE' && event.key === 'Tab') {
event.preventGridDefault();
}
}See more examples.
Callback triggered when a cell's content is copied. See the CellCopyArgs type.
Callback triggered when content is pasted into a cell. See the CellPasteArgs type.
Return the updated row; the grid will call onRowsChange with it.
Callback triggered when the active position changes. See the PositionChangeArgs type.
Callback triggered when the value of the active cell is dragged to fill other cells. When this prop is set, a drag handle is shown on the active cell if it is editable. Drag the handle up or down to fill the cells it passes over, or double-click it to fill all the cells below.
The grid calls onFill for each editable target cell. Return the updated target row; the grid will call onRowsChange with the updated rows. See the FillEvent type.
function onFill({ columnKey, sourceRow, targetRow }: FillEvent<Row>): Row {
return { ...targetRow, [columnKey]: sourceRow[columnKey as keyof Row] };
}
<DataGrid columns={columns} rows={rows} onRowsChange={setRows} onFill={onFill} />;Native DOM onScroll prop.
Callback triggered when a column is resized. The column parameter is the full CalculatedColumn object, and width is the new width in pixels.
Callback triggered when columns are reordered. The parameters are the key values of the source and target columns.
Default: true
This prop can be used to disable virtualization.
Custom renderers for cells, rows, and other components.
See the Renderers type for the full shape.
Example of replacing default components:
import { DataGrid, type Renderers } from 'react-data-grid';
const customRenderers: Renderers<Row, SummaryRow> = {
// Custom row render function
renderRow(key, props) {
return <CustomRow key={key} {...props} />;
},
// Custom cell render function
renderCell(key, props) {
return <CustomCell key={key} {...props} />;
},
// Custom checkbox render function
renderCheckbox(props) {
return <CustomCheckbox {...props} />;
},
// Custom sort status indicator
renderSortStatus(props) {
return <CustomSortIcon {...props} />;
},
// Custom empty state
noRowsFallback: <div>No data available</div>
};
<DataGrid columns={columns} rows={rows} renderers={customRenderers} />;The default <Row /> component can be wrapped via renderers.renderRow to add contexts or tweak props:
import { DataGrid, Row, type RenderRowProps } from 'react-data-grid';
interface MyRow {
id: number;
}
function myRowRenderer(key: React.Key, props: RenderRowProps<MyRow>) {
return (
<MyContext key={key} value={123}>
<Row {...props} />
</MyContext>
);
}
function MyGrid() {
return <DataGrid columns={columns} rows={rows} renderers={{ renderRow: myRowRenderer }} />;
}Function to apply custom class names to rows.
import { DataGrid } from 'react-data-grid';
function rowClass(row: Row, rowIdx: number) {
return rowIdx % 2 === 0 ? 'even' : 'odd';
}
function MyGrid() {
return <DataGrid columns={columns} rows={rows} rowClass={rowClass} />;
}useCallback to avoid re-rendering all rows on every render.
Custom class name for the header row.
<DataGrid columns={columns} rows={rows} headerRowClass="sticky-header" />This property sets the text direction of the grid. It defaults to 'ltr' (left-to-right). See the Direction type.
Setting direction to 'rtl' has the following effects:
- Columns flow from right to left
- Start-frozen columns are pinned on the right, and end-frozen columns are pinned on the left
- Column resize cursor is shown on the left edge of the column
- Scrollbar is moved to the left
Custom class name for the grid.
Custom styles for the grid.
ARIA role for the grid container. Defaults to grid.
The label of the grid. We recommend providing a label using aria-label or aria-labelledby.
The id of the element containing a label for the grid. We recommend providing a label using aria-label or aria-labelledby.
Total number of rows for assistive technologies.
A human-readable description of the grid.
If the grid has a caption or description, aria-describedby can be set on the grid element with a value referring to the element containing the description.
This prop can be used to add a test ID for testing. We recommend querying the grid by its role and name.
function MyGrid() {
return <DataGrid aria-label="my-grid" columns={columns} rows={rows} />;
}
test('grid', async () => {
await page.render(<MyGrid />);
const grid = page.getByRole('grid', { name: 'my-grid' });
});Optional attribute to help with Cypress (or similar) selectors.
TreeDataGrid is a component built on top of DataGrid to add hierarchical row grouping. This implements the Treegrid pattern.
How it works:
- The
groupByprop specifies which columns should be used for grouping - The
rowGrouperfunction groups rows by the specified column keys - Group rows are rendered with expand/collapse toggles
- Child rows are nested under their parent groups
- Groups can be expanded/collapsed by clicking the toggle or using keyboard navigation (←, →)
Keyboard Navigation:
- → (Right Arrow): Expand a collapsed group row when focused
- ← (Left Arrow): Collapse an expanded group row when focused, or navigate to the parent group
Unsupported Props:
The following DataGrid props are not supported in TreeDataGrid:
onFill- Drag-fill is disabled for tree gridsisRowSelectionDisabled- Row selection disabling is not availablerole-TreeDataGridmanages the ARIA rolearia-rowcount-TreeDataGridmanages the ARIA row count
Caveats:
- Group columns cannot be rendered under one column
- Group columns are automatically frozen and cannot be unfrozen
- Cell copy/paste does not work on group rows
- Column groups are not supported;
columnsmust beColumn[]
All DataGridProps are supported except those listed above. The columns prop only supports Column[] (no column groups). When rowHeight is a function, it receives RowHeightArgs instead of just the row. Additional props are listed below:
Required. An array of column keys to group by. The order determines the grouping hierarchy (first key is the top level, second key is nested under the first, etc.).
import { TreeDataGrid, type Column } from 'react-data-grid';
interface Row {
id: number;
country: string;
city: string;
name: string;
}
const columns: readonly Column<Row>[] = [
{ key: 'country', name: 'Country' },
{ key: 'city', name: 'City' },
{ key: 'name', name: 'Name' }
];
function MyGrid() {
return (
<TreeDataGrid
columns={columns}
rows={rows}
groupBy={['country', 'city']}
// ... other props
/>
);
}Required. A function that groups rows by the specified column key. Returns an object where keys are the group values and values are arrays of rows belonging to that group.
function rowGrouper(rows: readonly Row[], columnKey: string): Record<string, readonly Row[]> {
return Object.groupBy(rows, (row) => row[columnKey]);
}useCallback to prevent unnecessary re-renders.
Required. A set of group IDs that are currently expanded. Group IDs are generated by groupIdGetter.
import { useState } from 'react';
import { TreeDataGrid } from 'react-data-grid';
function MyGrid() {
const [expandedGroupIds, setExpandedGroupIds] = useState((): ReadonlySet<unknown> => new Set());
return (
<TreeDataGrid
expandedGroupIds={expandedGroupIds}
onExpandedGroupIdsChange={setExpandedGroupIds}
// ... other props
/>
);
}Required. Callback triggered when groups are expanded or collapsed.
Function to generate unique IDs for group rows. If not provided, a default implementation is used that concatenates parent and group keys with __.
useCallback to prevent unnecessary re-renders.
Note: Unlike DataGrid, the rowHeight function receives RowHeightArgs<R>, which includes a type property to distinguish between regular rows and group rows:
function getRowHeight(args: RowHeightArgs<Row>): number {
if (args.type === 'GROUP') {
return 50; // Custom height for group rows
}
return 35; // Height for regular rows
}
<TreeDataGrid rowHeight={getRowHeight} ... />The default row component. Can be wrapped via the renderers.renderRow prop.
RenderRowProps<TRow, TSummaryRow>
The default cell component. Can be wrapped via the renderers.renderCell prop.
RenderCellProps<TRow, TSummaryRow>
A component for rendering row selection checkboxes.
The same props as RenderCheckboxProps, with value: boolean in place of checked.
Low-level component used by renderToggleGroup to render the expand/collapse control. Useful if you build a custom group cell renderer.
RenderGroupCellContentProps<TRow, TSummaryRow>
Hook for managing header row selection state. Used within custom header cell renderers to implement custom "select all" functionality.
Returns:
isIndeterminate: boolean- Whether some (but not all) rows are selectedisRowSelected: boolean- Whether all rows are selectedonRowSelectionChange: (event: SelectHeaderRowEvent) => void- Callback to change selection state
Example:
import { useLayoutEffect, useRef } from 'react';
function CustomHeaderCell() {
const { isIndeterminate, isRowSelected, onRowSelectionChange } = useHeaderRowSelection();
const checkboxRef = useRef<HTMLInputElement>(null);
useLayoutEffect(() => {
if (checkboxRef.current) {
checkboxRef.current.indeterminate = isIndeterminate && !isRowSelected;
}
}, [isIndeterminate, isRowSelected]);
return (
<input
ref={checkboxRef}
type="checkbox"
checked={isRowSelected}
onChange={(event) => onRowSelectionChange({ checked: event.target.checked })}
/>
);
}Hook for managing row selection state. Used within custom cell renderers to implement custom row selection.
Returns:
isRowSelectionDisabled: boolean- Whether selection is disabled for this rowisRowSelected: boolean- Whether this row is selectedonRowSelectionChange: (event: SelectRowEvent<R>) => void- Callback to change selection state
Example:
function CustomSelectCell({ row }: RenderCellContentProps<Row>) {
const { isRowSelectionDisabled, isRowSelected, onRowSelectionChange } = useRowSelection();
return (
<input
type="checkbox"
disabled={isRowSelectionDisabled}
checked={isRowSelected}
onChange={(event) =>
onRowSelectionChange({
row,
checked: event.currentTarget.checked,
isShiftClick: event.nativeEvent.shiftKey
})
}
/>
);
}The default header cell content renderer. Renders sortable columns with sort indicators.
Props: RenderHeaderCellContentProps<TRow, TSummaryRow>
Example:
import { renderHeaderCell, type Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [
{
key: 'name',
name: 'Name',
sortable: true,
renderHeaderCell
}
];A basic text editor provided for convenience.
Props: RenderEditCellContentProps<TRow, TSummaryRow>
Example:
import { renderTextEditor, type Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [
{
key: 'title',
name: 'Title',
renderEditCell: renderTextEditor
}
];Renders the sort direction arrow icon.
Props: RenderSortIconProps
Renders the sort priority number for multi-column sorting.
Props: RenderSortPriorityProps
Renders a checkbox input with proper styling and accessibility.
Props: RenderCheckboxProps
Example:
import { DataGrid, renderCheckbox } from 'react-data-grid';
<DataGrid
renderers={{
renderCheckbox: (props) => renderCheckbox({ ...props, 'aria-label': 'Select row' })
}}
/>;The default group cell content renderer for the columns used for grouping (groupBy prop). This renders the expand/collapse toggle.
Props: RenderGroupCellContentProps<TRow, TSummaryRow>
Example:
import { renderToggleGroup, type Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [
{
key: 'group',
name: 'Group',
renderGroupCell: renderToggleGroup
}
];The default cell content renderer that renders the value of row[column.key].
Props: RenderCellContentProps<TRow, TSummaryRow>
Example:
import { renderValue, type Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [
{
key: 'title',
name: 'Title',
renderCell: renderValue
}
];Context for providing default renderers to DataGrids in your app.
Example:
import {
DataGridRenderersContext,
renderCheckbox,
renderSortIcon,
renderSortPriority,
type Renderers
} from 'react-data-grid';
// custom implementations of renderers
const defaultGridRenderers: Renderers<unknown, unknown> = {
renderCheckbox,
renderSortStatus(props) {
return (
<>
{renderSortIcon(props)}
{renderSortPriority(props)}
</>
);
}
};
function AppProvider({ children }) {
return (
<DataGridRenderersContext value={defaultGridRenderers}>{children}</DataGridRenderersContext>
);
}A pre-configured column for row selection. Includes checkbox renderers for the header row, regular rows, and group rows.
Example:
import { DataGrid, SelectColumn, type Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [SelectColumn, ...otherColumns];
function rowKeyGetter(row: Row) {
return row.id;
}
function MyGrid() {
return (
<DataGrid
columns={columns}
rows={rows}
rowKeyGetter={rowKeyGetter}
selectedRows={selectedRows}
onSelectedRowsChange={setSelectedRows}
/>
);
}The key used for the SelectColumn. Useful for identifying or filtering the select column.
Example:
import { SELECT_COLUMN_KEY } from 'react-data-grid';
const nonSelectColumns = columns.filter((column) => column.key !== SELECT_COLUMN_KEY);Defines the configuration for a column in the grid.
See also: columns prop on <DataGrid />
The name of the column. Displayed in the header cell by default.
A unique key to distinguish each column.
Default: auto
Width can be any valid CSS grid column value. If not specified, it will be determined automatically based on grid width and specified widths of other columns.
const columns: Column<Row>[] = [
{
key: 'id',
name: 'ID',
width: 80, // Fixed width in pixels
resizable: false
},
{
key: 'name',
name: 'Name',
width: '30%', // Percentage width
minWidth: 100,
maxWidth: 400
},
{
key: 'description',
name: 'Description'
// No width specified - automatically sized
}
];Other examples:
width: 80, // pixels
width: '25%',
width: 'max-content',
width: 'minmax(100px, max-content)',max-content can be used to expand the column to show all the content. Note that the grid is only able to calculate column width for visible rows.
Default: 50 pixels
Minimum column width in pixels.
Maximum column width in pixels.
Class name(s) for cells. Can be a string or a function that returns a class name based on the row.
const columns: Column<Row>[] = [
{
key: 'status',
name: 'Status',
cellClass: (row) => `status-${row.status}`
},
{
key: 'price',
name: 'Price',
cellClass: 'text-right' // Static class
}
];.status-active {
color: green;
font-weight: bold;
}
.status-inactive {
color: gray;
}
.text-right {
text-align: right;
}Class name(s) for the header cell.
Class name(s) for summary cells. Can be a string or a function that returns a class name based on the summary row.
Render function to render the content of cells.
Render function to render the content of the header cell.
Render function to render the content of summary cells.
Render function to render the content of group cells when using TreeDataGrid.
Render function to render the content of edit cells. When set, the column is automatically set to be editable.
Control whether cells can be edited with renderEditCell.
Function to determine how many columns this cell should span. Returns the number of columns to span, or undefined for no spanning. See the ColSpanArgs type.
Example:
import type { Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [
{
key: 'title',
name: 'Title',
colSpan(args) {
if (args.type === 'ROW' && args.row.isFullWidth) {
return 5; // Span 5 columns for full-width rows
}
return undefined;
}
}
];Default: false
Determines whether the column is frozen, and on which edge. Frozen columns stay in place when the grid is scrolled horizontally. See the ColumnFrozen type.
'start'(ortruefor backward compatibility) — pins the column to the start edge (left in LTR, right in RTL).'end'— pins the column to the end edge (right in LTR, left in RTL).false(default) — the column scrolls with the rest of the grid.
const columns: readonly Column<Row>[] = [
{ key: 'id', name: 'ID', frozen: 'start' },
{ key: 'name', name: 'Name' },
{ key: 'actions', name: 'Actions', frozen: 'end' }
];Default: false
Enable resizing of the column.
Default: false
Enable sorting of the column.
Default: false
Enable dragging of the column.
Default: false
Sets the column sort order to be descending instead of ascending the first time the column is sorted.
Options for cell editing.
Default: false
Render the cell content in addition to the edit cell content. Enable this option when the editor is rendered outside the grid, like a modal for example.
Default: true
Commit changes when clicking outside the cell.
Default: true
Close the editor when the row value changes externally.
Defines a group of columns that share a common header.
interface ColumnGroup<R, SR = unknown> {
/** The name of the column group. It will be displayed in the header cell */
readonly name: string | ReactElement;
readonly headerCellClass?: Maybe<string>;
readonly children: readonly ColumnOrColumnGroup<R, SR>[];
}Example:
import type { ColumnOrColumnGroup } from 'react-data-grid';
const columns: readonly ColumnOrColumnGroup<Row>[] = [
{
name: 'Personal Info',
children: [
{ key: 'firstName', name: 'First Name' },
{ key: 'lastName', name: 'Last Name' }
]
}
];See also: ColumnOrColumnGroup
Union type representing either a Column or a ColumnGroup.
See also: columns prop on <DataGrid />
Extends Column with additional computed properties used internally by the grid. This is the type passed to render functions. Every Column property is set: the ones with a default value, like width and renderCell, are resolved to their default value when not set, and the others are undefined when not set.
interface CalculatedColumn<TRow, TSummaryRow = unknown> extends Column<TRow, TSummaryRow> {
/** The column group that contains the column, or `undefined` if the column is not in a group */
readonly parent: CalculatedColumnParent<TRow, TSummaryRow> | undefined;
/** The index of the column in the grid. Column groups are flattened and frozen columns are moved to their edge, so it can differ from the column's index in `columns` */
readonly idx: number;
/** Header row level, counted from the bottom header row: always `0` for columns, and negative for column groups */
readonly level: number;
readonly width: number | string;
readonly minWidth: number;
readonly maxWidth: number | undefined;
readonly resizable: boolean;
readonly sortable: boolean;
readonly draggable: boolean;
readonly frozen: ColumnFrozen;
readonly renderCell: (props: RenderCellContentProps<TRow, TSummaryRow>) => ReactNode;
readonly renderHeaderCell: (props: RenderHeaderCellContentProps<TRow, TSummaryRow>) => ReactNode;
// Always set, `undefined` when not set on the column
readonly cellClass: Column<TRow, TSummaryRow>['cellClass'];
readonly headerCellClass: Column<TRow, TSummaryRow>['headerCellClass'];
readonly summaryCellClass: Column<TRow, TSummaryRow>['summaryCellClass'];
readonly renderSummaryCell: Column<TRow, TSummaryRow>['renderSummaryCell'];
readonly renderGroupCell: Column<TRow, TSummaryRow>['renderGroupCell'];
readonly renderEditCell: Column<TRow, TSummaryRow>['renderEditCell'];
readonly editable: Column<TRow, TSummaryRow>['editable'];
readonly colSpan: Column<TRow, TSummaryRow>['colSpan'];
readonly sortDescendingFirst: Column<TRow, TSummaryRow>['sortDescendingFirst'];
readonly editorOptions: Column<TRow, TSummaryRow>['editorOptions'];
}See also: Column, onColumnResize prop on <DataGrid />
Represents a parent column group in the calculated column structure.
interface CalculatedColumnParent<R, SR> {
readonly name: string | ReactElement;
readonly parent: CalculatedColumnParent<R, SR> | undefined;
readonly idx: number;
readonly colSpan: number;
readonly level: number;
readonly headerCellClass?: Maybe<string>;
}See also: CalculatedColumn
Union type representing either a CalculatedColumnParent or a CalculatedColumn.
type CalculatedColumnOrColumnGroup<R, SR> = CalculatedColumnParent<R, SR> | CalculatedColumn<R, SR>;See also: CalculatedColumn, CalculatedColumnParent
Default options applied to all columns.
type DefaultColumnOptions<TRow, TSummaryRow> = Pick<
Column<TRow, TSummaryRow>,
| 'renderCell'
| 'renderHeaderCell'
| 'width'
| 'minWidth'
| 'maxWidth'
| 'resizable'
| 'sortable'
| 'draggable'
>;See also: defaultColumnOptions prop on <DataGrid />
Whether a column is frozen, and on which edge.
type ColumnFrozen = boolean | 'start' | 'end';See also: column.frozen
Props passed to custom cell content renderers (column.renderCell).
interface RenderCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
isCellEditable: boolean;
tabIndex: number;
onRowChange: (row: TRow) => void;
}Example:
import type { RenderCellContentProps } from 'react-data-grid';
function renderCell({ row, column, onRowChange }: RenderCellContentProps<MyRow>) {
return (
<div>
{row[column.key]}
<button onClick={() => onRowChange({ ...row, updated: true })}>Update</button>
</div>
);
}See also: column.renderCell, renderValue function
Props passed to custom header cell content renderers (column.renderHeaderCell).
interface RenderHeaderCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
sortDirection: SortDirection | undefined;
priority: number | undefined;
tabIndex: number;
}See also: column.renderHeaderCell, renderHeaderCell function
Props passed to custom editors (column.renderEditCell).
interface RenderEditCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
onRowChange: (row: TRow, commitChanges?: boolean) => void;
onClose: (commitChanges?: boolean, shouldFocus?: boolean) => void;
}Example:
import type { RenderEditCellContentProps } from 'react-data-grid';
function renderEditor({ row, column, onRowChange, onClose }: RenderEditCellContentProps<MyRow>) {
return (
<input
autoFocus
value={row[column.key]}
onChange={(event) => onRowChange({ ...row, [column.key]: event.target.value })}
onBlur={() => onClose(true)}
/>
);
}See also: column.renderEditCell, renderTextEditor function
Props passed to summary cell content renderers (column.renderSummaryCell).
interface RenderSummaryCellContentProps<TSummaryRow, TRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TSummaryRow;
tabIndex: number;
}See also: column.renderSummaryCell
Props passed to group cell content renderers (column.renderGroupCell) when using TreeDataGrid.
interface RenderGroupCellContentProps<TRow, TSummaryRow = unknown> {
groupKey: unknown;
column: CalculatedColumn<TRow, TSummaryRow>;
row: GroupRow<TRow>;
childRows: readonly TRow[];
isExpanded: boolean;
tabIndex: number;
toggleGroup: () => void;
}See also: column.renderGroupCell, renderToggleGroup function, <ToggleGroup />
Props passed to custom row renderers.
interface RenderRowProps<TRow, TSummaryRow = unknown> {
row: TRow;
/**
* Calls `callback` for each cell to render in the row, and returns the results.
* `activeIdx` is the column index of the row's active cell, if any: that cell is rendered even when it is scrolled out of view.
* If virtualization would leave out the active row, it is rendered with only its active cell, if any.
* `colSpanArgs` is passed to `column.colSpan`, and the columns that a cell spans are skipped, even the active one.
* The callback receives the cell's column, whether the cell is active, its `colSpan`, and its index in the results.
*/
mapViewportColumns: MapViewportColumns<TRow, TSummaryRow>;
rowIdx: number;
activeCellIdx: number | undefined;
isRowSelectionDisabled: boolean;
isRowSelected: boolean;
gridRowStart: number;
draggedOverCellIdx: number | undefined;
activeCellEditor: ReactElement<EditCellProps<TRow, TSummaryRow>> | undefined;
onRowChange: (column: CalculatedColumn<TRow, TSummaryRow>, rowIdx: number, newRow: TRow) => void;
rowClass: Maybe<(row: TRow, rowIdx: number) => Maybe<string>>;
isTreeGrid: boolean;
setActivePosition: (position: Position, options?: SetActivePositionOptions) => void;
// ... and DOM props, cell event handlers (onCellMouseDown, onCellClick, onCellDoubleClick, onCellContextMenu)
}See also: renderers.renderRow, <Row />, MapViewportColumns
Type of mapViewportColumns in RenderRowProps. This helper type is not exported; the shape is shown for reference.
type MapViewportColumns<TRow, TSummaryRow> = <T>(
activeIdx: number | undefined,
colSpanArgs: ColSpanArgs<TRow, TSummaryRow> | undefined,
callback: (
column: CalculatedColumn<TRow, TSummaryRow>,
isCellActive: boolean,
colSpan: number | undefined,
index: number
) => T
) => T[];See also: RenderRowProps, ColSpanArgs
Props passed to the cell renderer when using renderers.renderCell.
interface RenderCellProps<TRow, TSummaryRow> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
colSpan: number | undefined;
isDraggedOver: boolean;
isCellActive: boolean;
onRowChange: (column: CalculatedColumn<TRow, TSummaryRow>, rowIdx: number, newRow: TRow) => void;
setActivePosition: (position: Position, options?: SetActivePositionOptions) => void;
// ... and DOM props, cell event handlers (onCellMouseDown, onCellClick, onCellDoubleClick, onCellContextMenu)
}See also: renderers.renderCell, <Cell />
Props for custom checkbox renderers.
interface RenderCheckboxProps {
/** Whether the checkbox is checked */
checked?: boolean | undefined;
/** Whether the checkbox is in an indeterminate state, like the select all checkbox when only some rows are selected */
indeterminate?: boolean | undefined;
/** Whether the checkbox is disabled */
disabled?: boolean | undefined;
/** Called when the checkbox is toggled. `shift` is `true` if the Shift key was held, to select a range of rows */
onChange: (checked: boolean, shift: boolean) => void;
/** `0` when the checkbox's cell is active and `-1` otherwise, so the grid can move focus from the cell to the checkbox */
tabIndex?: number | undefined;
/** Accessible label for the checkbox */
'aria-label'?: string | undefined;
/** ID of the element that labels the checkbox */
'aria-labelledby'?: string | undefined;
}See also: renderCheckbox function, renderers.renderCheckbox, <SelectCheckbox />
Props for custom sort status renderers.
interface RenderSortStatusProps extends RenderSortIconProps, RenderSortPriorityProps {}See also: renderers.renderSortStatus
Props for custom sort icon renderers.
interface RenderSortIconProps {
/** The sort direction of the column, or `undefined` if it is not sorted */
sortDirection: SortDirection | undefined;
}See also: renderSortIcon function
Props for custom sort priority renderers.
interface RenderSortPriorityProps {
/** The column's position in `sortColumns`, starting at 1, when sorting by multiple columns, or `undefined` otherwise */
priority: number | undefined;
}See also: renderSortPriority function
Custom renderer configuration for the grid.
interface Renderers<TRow, TSummaryRow> {
renderCell?: Maybe<(key: Key, props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>;
renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>;
renderRow?: Maybe<(key: Key, props: RenderRowProps<TRow, TSummaryRow>) => ReactNode>;
renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>;
noRowsFallback?: Maybe<ReactNode>;
}See also: renderers prop on <DataGrid />, DataGridRenderersContext
Arguments passed to cell mouse event handlers.
interface CellMouseArgs<TRow, TSummaryRow = unknown> {
/** The column object of the cell. */
column: CalculatedColumn<TRow, TSummaryRow>;
/** The row object of the cell. */
row: TRow;
/** The row index of the cell. */
rowIdx: number;
/** Function to manually focus the cell. Pass `true` to immediately start editing. */
setActivePosition: (enableEditor?: boolean) => void;
}Example:
import type { CellMouseArgs, CellMouseEvent } from 'react-data-grid';
function onCellClick(args: CellMouseArgs<Row>, event: CellMouseEvent) {
console.log('Clicked cell at row', args.rowIdx, 'column', args.column.key);
args.setActivePosition(true); // Focus and start editing
}See also: onCellMouseDown, onCellClick, onCellDoubleClick, and onCellContextMenu props on <DataGrid />
Handler type used by onCellMouseDown, onCellClick, onCellDoubleClick, and onCellContextMenu. This helper type is not exported; the shape is shown for reference.
type CellMouseEventHandler<TRow, TSummaryRow> = Maybe<
(args: CellMouseArgs<TRow, TSummaryRow>, event: CellMouseEvent) => void
>;Adds grid-specific methods to a React event. This helper type is not exported; the shape is shown for reference.
type CellEvent<E extends React.SyntheticEvent<HTMLDivElement>> = E & {
/** Prevents the default grid behavior for this event */
preventGridDefault: () => void;
/** Returns whether `preventGridDefault` was called */
isGridDefaultPrevented: () => boolean;
};See also: CellMouseEvent, CellKeyboardEvent
Extends React.MouseEvent<HTMLDivElement> with grid-specific methods.
type CellMouseEvent = CellEvent<React.MouseEvent<HTMLDivElement>>;Example:
import type { CellMouseArgs, CellMouseEvent } from 'react-data-grid';
function onCellMouseDown(args: CellMouseArgs<Row>, event: CellMouseEvent) {
if (args.column.key === 'actions') {
event.preventGridDefault(); // Prevent cell focus
}
}See also: onCellMouseDown, onCellClick, onCellDoubleClick, and onCellContextMenu props on <DataGrid />
Arguments passed to the onCellKeyDown handler. The shape differs based on whether the cell is in ACTIVE or EDIT mode.
ACTIVE mode:
interface ActiveCellKeyDownArgs<TRow, TSummaryRow = unknown> {
mode: 'ACTIVE';
/**
* column object of the active position,
* undefined if the active position is a row instead of a cell
*/
column: CalculatedColumn<TRow, TSummaryRow> | undefined;
row: TRow;
rowIdx: number;
setActivePosition: (position: Position, options?: SetActivePositionOptions) => void;
}EDIT mode:
interface EditCellKeyDownArgs<TRow, TSummaryRow = unknown> {
mode: 'EDIT';
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
navigate: () => void;
onClose: (commitChanges?: boolean, shouldFocus?: boolean) => void;
}Example:
import type { CellKeyboardEvent, CellKeyDownArgs } from 'react-data-grid';
function onCellKeyDown(args: CellKeyDownArgs<Row>, event: CellKeyboardEvent) {
if (args.mode === 'EDIT' && event.key === 'Escape') {
args.onClose(false); // Close without committing
event.preventGridDefault();
}
}See also: onCellKeyDown prop on <DataGrid />
Extends React.KeyboardEvent<HTMLDivElement> with grid-specific methods.
type CellKeyboardEvent = CellEvent<React.KeyboardEvent<HTMLDivElement>>;See also: onCellKeyDown prop on <DataGrid />
Type alias for React.ClipboardEvent<HTMLDivElement>. Used for copy and paste events. This helper type is not exported; the shape is shown for reference.
type CellClipboardEvent = React.ClipboardEvent<HTMLDivElement>;See also: onCellCopy and onCellPaste props on <DataGrid />
Arguments passed to onCellCopy.
interface CellCopyArgs<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
}See also: onCellCopy prop on <DataGrid />
Arguments passed to onCellPaste.
interface CellPasteArgs<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
}See also: onCellPaste prop on <DataGrid />
Arguments passed to onActivePositionChange.
interface PositionChangeArgs<TRow, TSummaryRow = unknown> {
/** row index of the active position */
rowIdx: number;
/**
* row object of the active position,
* undefined if the active position is on a header or summary row
*/
row: TRow | undefined;
/**
* column object of the active position,
* undefined if the active position is a row instead of a cell
*/
column: CalculatedColumn<TRow, TSummaryRow> | undefined;
}See also: onActivePositionChange prop on <DataGrid />
Arguments passed to the colSpan function.
type ColSpanArgs<TRow, TSummaryRow> =
| { readonly type: 'HEADER' }
| { readonly type: 'ROW'; readonly row: TRow }
| { readonly type: 'SUMMARY'; readonly row: TSummaryRow };Example:
import type { Column } from 'react-data-grid';
const columns: readonly Column<Row>[] = [
{
key: 'title',
name: 'Title',
colSpan(args) {
if (args.type === 'ROW' && args.row.isFullWidth) {
return 3; // Span 3 columns
}
return undefined;
}
}
];See also: column.colSpan
Arguments passed to TreeDataGrid's rowHeight prop when it is a function.
type RowHeightArgs<TRow> = { type: 'ROW'; row: TRow } | { type: 'GROUP'; row: GroupRow<TRow> };Example:
function getRowHeight(args: RowHeightArgs<Row>): number {
if (args.type === 'GROUP') {
return 40;
}
return args.row.isLarge ? 60 : 35;
}
<TreeDataGrid rowHeight={getRowHeight} ... />See also: rowHeight prop on <TreeDataGrid />
Describes a sorted column.
interface SortColumn {
readonly columnKey: string;
readonly direction: SortDirection;
}See also: sortColumns and onSortColumnsChange props on <DataGrid />
type SortDirection = 'ASC' | 'DESC';See also: SortColumn
Data provided to the onRowsChange callback.
interface RowsChangeData<R, SR = unknown> {
/** Indexes of the rows that changed */
indexes: number[];
/** The column of the cells that changed */
column: CalculatedColumn<R, SR>;
}See also: onRowsChange prop on <DataGrid />
Event object for row selection changes.
interface SelectRowEvent<TRow> {
row: TRow;
checked: boolean;
isShiftClick: boolean;
}See also: useRowSelection hook
Event object for header row selection changes.
interface SelectHeaderRowEvent {
checked: boolean;
}See also: useHeaderRowSelection hook
Event object for drag-fill operations.
interface FillEvent<TRow> {
columnKey: string;
sourceRow: TRow;
targetRow: TRow;
}See also: onFill prop on <DataGrid />
Handle type assigned to a grid's ref for programmatic grid control.
interface DataGridHandle {
element: HTMLDivElement | null;
scrollToCell: (position: PartialPosition) => void;
setActivePosition: (position: Position, options?: SetActivePositionOptions) => void;
}Example:
import { useRef } from 'react';
import { DataGrid, type DataGridHandle } from 'react-data-grid';
function MyGrid() {
const gridRef = useRef<DataGridHandle>(null);
function scrollToTop() {
gridRef.current?.scrollToCell({ rowIdx: 0 });
}
return <DataGrid ref={gridRef} columns={columns} rows={rows} />;
}See also: ref prop on <DataGrid />
Represents a cell position in the grid. This helper type is not exported; the shape is shown for reference.
interface Position {
/** Column index, or `-1` for the whole row in `TreeDataGrid` */
readonly idx: number;
/** Row index: `0` is the first row, header rows and top summary rows have negative indexes, and bottom summary rows come after the last row */
readonly rowIdx: number;
}See also: DataGridHandle, CellKeyDownArgs
Position for scrolling to a cell. Both fields are optional: omit idx to scroll to a row, or omit rowIdx to scroll to a column. This helper type is not exported; the shape is shown for reference.
interface PartialPosition {
readonly idx?: Maybe<number>;
readonly rowIdx?: Maybe<number>;
}See also: DataGridHandle
Options for programmatically updating the grid's active position.
interface SetActivePositionOptions {
enableEditor?: Maybe<boolean>;
shouldFocus?: Maybe<boolean>;
}See also: DataGridHandle, CellKeyDownArgs
A map of column widths.
type ColumnWidths = ReadonlyMap<string, ColumnWidth>;See also: columnWidths and onColumnWidthsChange props on <DataGrid />
Represents a single column's width.
interface ColumnWidth {
/** `'resized'` if the user resized the column, or `'measured'` if the grid measured it */
readonly type: 'resized' | 'measured';
/** The width in pixels */
readonly width: number;
}See also: ColumnWidths
Text direction of the grid.
type Direction = 'ltr' | 'rtl';See also: direction prop on <DataGrid />
Represents a group row in TreeDataGrid. This helper type is not exported; the shape is shown for reference.
interface GroupRow<TRow> {
readonly childRows: readonly TRow[];
readonly id: string;
readonly parentId: unknown;
readonly groupKey: unknown;
readonly isExpanded: boolean;
readonly level: number;
readonly posInSet: number;
readonly setSize: number;
readonly startRowIndex: number;
}See also: RenderGroupCellContentProps, RowHeightArgs, <TreeDataGrid />
Utility type for optional values. This helper type is not exported; the shape is shown for reference.
type Maybe<T> = T | undefined | null;R,TRow: Row typeSR,TSummaryRow: Summary row typeK: Row key type