Overview
Rows represent the data displayed in your grid. React Data Grid accepts any array of objects and provides efficient rendering through virtualization.
Basic Row Setup
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} />;
}
Row Key Getter
Provide a unique key for each row to enable selection and optimize performance:
Function that returns a unique identifier for each row.
import { useState } from 'react';
import { DataGrid, SelectColumn } from 'react-data-grid';
interface Row {
id: number;
name: string;
}
function rowKeyGetter(row: Row) {
return row.id;
}
function MyGrid() {
const [selectedRows, setSelectedRows] = useState((): ReadonlySet<number> => new Set());
return (
<DataGrid
columns={[SelectColumn, ...otherColumns]}
rows={rows}
rowKeyGetter={rowKeyGetter}
selectedRows={selectedRows}
onSelectedRowsChange={setSelectedRows}
/>
);
}
While optional, rowKeyGetter is highly recommended for optimal performance. The returned value sets the key prop on row elements.
Define rowKeyGetter outside your component or memoize with useCallback to prevent unnecessary re-renders.
Updating Rows
Use the onRowsChange callback to handle row updates:
onRowsChange
(rows: R[], data: RowsChangeData<R, SR>) => void
Callback triggered when rows are modified through editing or other grid interactions.Parameters:
rows: New array with updated rows and unchanged rows
data.indexes: Array of row indexes that changed
data.column: The column where the change occurred
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}
/>
);
}
Row Heights
rowHeight
number | ((row: R) => number)
default:35
Height of each row in pixels. Can be a fixed number or a function for dynamic heights.
Fixed Height
<DataGrid columns={columns} rows={rows} rowHeight={50} />
Dynamic Height
function getRowHeight(row: Row) {
return row.isExpanded ? 100 : 35;
}
<DataGrid columns={columns} rows={rows} rowHeight={getRowHeight} />
When using dynamic row heights with large datasets (1000+ rows), ensure the function identity remains stable to avoid performance issues. Use a static function or memoize with useCallback.
Row Styling
rowClass
(row: R, rowIdx: number) => string | null
Function to apply custom CSS classes to rows.
function rowClass(row: Row, rowIdx: number) {
if (row.isDisabled) return 'row-disabled';
return rowIdx % 2 === 0 ? 'row-even' : 'row-odd';
}
<DataGrid
columns={columns}
rows={rows}
rowClass={rowClass}
/>
Define rowClass outside your component or memoize with useCallback to avoid re-rendering all rows on every render.
React Data Grid is optimized for efficient rendering:
Virtualization
Only visible rows are rendered in the DOM. Rows outside the viewport are not rendered, enabling smooth performance with large datasets.
Individual Row Updates
Row components are memoized. Updating a single row object only re-renders that specific row:
// ✅ Good: Only changed row is re-rendered
setRows(rows.map((row, idx) =>
idx === targetIdx ? { ...row, updated: true } : row
));
// ❌ Avoid: Creates new references for all rows
setRows(rows.map((row) => ({ ...row })));
Array Reference Matters
Changing the array reference triggers viewport and layout recalculations:
// ✅ Good: New array, but unchanged row objects are reused
const updatedRows = [...rows];
updatedRows[index] = updatedRow;
setRows(updatedRows);
// ⚠️ Triggers recalculation even if rows are identical
setRows([...rows]);
When updating rows, create a new array but reuse unchanged row objects for optimal performance.
Summary Rows
Display summary information at the top or bottom of the grid:
Rows pinned at the top for summary purposes.
Rows pinned at the bottom for summary purposes.
summaryRowHeight
number
default:"rowHeight or 35"
Height of summary rows in pixels.
interface SummaryRow {
id: string;
totalPrice: number;
}
const summaryRows: readonly SummaryRow[] = [
{ id: 'total', totalPrice: 10000 }
];
<DataGrid
columns={columns}
rows={rows}
topSummaryRows={summaryRows}
summaryRowHeight={40}
/>
Empty State
Display a custom message when there are no rows:
import { DataGrid, type Renderers } from 'react-data-grid';
const customRenderers: Renderers<Row, SummaryRow> = {
noRowsFallback: <div>No data available</div>
};
<DataGrid
columns={columns}
rows={[]}
renderers={customRenderers}
/>
TypeScript Types
interface DataGridProps<R, SR = unknown, K extends Key = Key> {
/** Array of row data */
rows: readonly R[];
/** Function to return unique key for each row */
rowKeyGetter?: Maybe<(row: R) => K>;
/** Callback when rows are changed */
onRowsChange?: Maybe<(rows: R[], data: RowsChangeData<R, SR>) => void>;
/** Row height in pixels or function */
rowHeight?: Maybe<number | ((row: R) => number)>;
/** Function to apply custom classes to rows */
rowClass?: Maybe<(row: R, rowIdx: number) => Maybe<string>>;
/** Summary rows at the top */
topSummaryRows?: Maybe<readonly SR[]>;
/** Summary rows at the bottom */
bottomSummaryRows?: Maybe<readonly SR[]>;
/** Height of summary rows */
summaryRowHeight?: Maybe<number>;
}
interface RowsChangeData<R, SR = unknown> {
/** Array of indexes that changed */
indexes: number[];
/** Column where the change occurred */
column: CalculatedColumn<R, SR>;
}