What is react-data-grid?
react-data-grid is a powerful and feature-rich data grid component for React applications. It provides a wide range of functionalities for displaying, editing, and managing data in a tabular format. It is highly customizable and supports various features such as sorting, filtering, grouping, and more.
What are react-data-grid's main functionalities?
Basic Grid
This code demonstrates a basic data grid with three columns: ID, Title, and Count. It displays two rows of data.
import React from 'react';
import ReactDataGrid from 'react-data-grid';
const columns = [
{ key: 'id', name: 'ID' },
{ key: 'title', name: 'Title' },
{ key: 'count', name: 'Count' }
];
const rows = [
{ id: 0, title: 'Example', count: 20 },
{ id: 1, title: 'Demo', count: 40 }
];
function BasicGrid() {
return <ReactDataGrid columns={columns} rows={rows} />;
}
export default BasicGrid;
Editable Grid
This code demonstrates an editable data grid where users can edit the values in the cells. The changes are reflected in the grid's state.
import React from 'react';
import ReactDataGrid from 'react-data-grid';
const columns = [
{ key: 'id', name: 'ID', editable: true },
{ key: 'title', name: 'Title', editable: true },
{ key: 'count', name: 'Count', editable: true }
];
const rows = [
{ id: 0, title: 'Example', count: 20 },
{ id: 1, title: 'Demo', count: 40 }
];
function EditableGrid() {
const [gridRows, setGridRows] = React.useState(rows);
const onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
const updatedRows = gridRows.slice();
for (let i = fromRow; i <= toRow; i++) {
updatedRows[i] = { ...updatedRows[i], ...updated };
}
setGridRows(updatedRows);
};
return (
<ReactDataGrid
columns={columns}
rows={gridRows}
onRowsUpdate={onGridRowsUpdated}
/>
);
}
export default EditableGrid;
Sortable Grid
This code demonstrates a sortable data grid where users can sort the rows by clicking on the column headers. The sorting direction can be ascending or descending.
import React from 'react';
import ReactDataGrid from 'react-data-grid';
const columns = [
{ key: 'id', name: 'ID', sortable: true },
{ key: 'title', name: 'Title', sortable: true },
{ key: 'count', name: 'Count', sortable: true }
];
const rows = [
{ id: 0, title: 'Example', count: 20 },
{ id: 1, title: 'Demo', count: 40 }
];
function SortableGrid() {
const [gridRows, setGridRows] = React.useState(rows);
const [sortColumn, setSortColumn] = React.useState(null);
const [sortDirection, setSortDirection] = React.useState(null);
const onGridSort = (column, direction) => {
const sortedRows = [...gridRows].sort((a, b) => {
if (direction === 'ASC') {
return a[column] > b[column] ? 1 : -1;
} else if (direction === 'DESC') {
return a[column] < b[column] ? 1 : -1;
} else {
return 0;
}
});
setGridRows(sortedRows);
setSortColumn(column);
setSortDirection(direction);
};
return (
<ReactDataGrid
columns={columns}
rows={gridRows}
onGridSort={onGridSort}
sortColumn={sortColumn}
sortDirection={sortDirection}
/>
);
}
export default SortableGrid;
Other packages similar to react-data-grid
ag-grid-react
ag-grid-react is a feature-rich data grid component for React applications. It offers a wide range of functionalities including sorting, filtering, grouping, and more. It is highly customizable and supports large datasets efficiently. Compared to react-data-grid, ag-grid-react provides more advanced features and better performance for large datasets.
react-table
react-table is a lightweight and flexible data table component for React. It provides basic functionalities such as sorting, filtering, and pagination. It is highly customizable and easy to use. Compared to react-data-grid, react-table is more lightweight and easier to integrate but may lack some advanced features.
material-table
material-table is a data table component for React based on Material-UI. It provides functionalities such as sorting, filtering, grouping, and more. It is highly customizable and integrates well with Material-UI components. Compared to react-data-grid, material-table offers a more modern and visually appealing design but may have a steeper learning curve.
react-data-grid

The DataGrid component is designed to handle large datasets efficiently while offering a rich set of features for customization and interactivity.
Features
Links
Installation
to install react-data-grid
, use npm or yarn:
npm install react-data-grid
yarn add react-data-grid
Additionally, 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.
Getting started
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 } from 'react-data-grid';
const columns = [
{ key: 'id', name: 'ID' },
{ key: 'title', name: 'Title' }
];
const rows = [
{ id: 0, title: 'Example' },
{ id: 1, title: 'Demo' }
];
function App() {
return <DataGrid columns={columns} rows={rows} />;
}
API Reference
Components
<DataGrid />
DataGridProps
columns: readonly Column<R, SR>[]
See Column
.
An array of column definitions. Each column should have a key and name.
:warning: Passing a new columns
array will trigger a re-render for the whole grid, avoid changing it as much as possible for optimal performance.
rows: readonly R[]
An array of rows, the rows data can be of any type.
topSummaryRows?: Maybe<readonly SR[]>
Rows pinned at the top of the grid for summary purposes.
bottomSummaryRows?: Maybe<readonly SR[]>
Rows pinned at the bottom of the grid for summary purposes.
rowKeyGetter?: Maybe<(row: R) => K>
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} />;
}
:bulb: 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.
onRowsChange?: Maybe<(rows: R[], data: RowsChangeData<R, SR>) => void>
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.
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} />;
}
rowHeight?: Maybe<number | ((row: R) => number)>
Default: 35
pixels
Height of each row in pixels. A function can be used to set different row heights.
Default: 35
pixels
Height of the header row in pixels.
summaryRowHeight?: Maybe<number>
Default: 35
pixels
Height of each summary row in pixels.
selectedRows?: Maybe<ReadonlySet<K>>
A set of selected row keys. rowKeyGetter
is required for row selection to work.
isRowSelectionDisabled?: Maybe<(row: NoInfer<R>) => boolean>
Function to determine if row selection is disabled for a specific row.
onSelectedRowsChange?: Maybe<(selectedRows: Set<K>) => void>
Callback triggered when the selection changes.
import { useState } from 'react';
import { DataGrid, SelectColumn } from 'react-data-grid';
const rows: readonly Rows[] = [...];
const columns: readonly Column<Row>[] = [
SelectColumn,
];
function MyGrid() {
const [selectedRows, setSelectedRows] = useState((): ReadonlySet<number> => new Set());
return (
<DataGrid
rowKeyGetter={rowKeyGetter}
columns={columns}
rows={rows}
selectedRows={selectedRows}
isRowSelectionDisabled={isRowSelectionDisabled}
onSelectedRowsChange={setSelectedRows}
/>
);
}
function rowKeyGetter(row: Row) {
return row.id;
}
function isRowSelectionDisabled(row: Row) {
return !row.isActive;
}
sortColumns?: Maybe<readonly SortColumn[]>
An array of sorted columns.
onSortColumnsChange?: Maybe<(sortColumns: SortColumn[]) => void>
Callback triggered when sorting changes.
import { useState } from 'react';
import { DataGrid, SelectColumn } from 'react-data-grid';
const rows: readonly Rows[] = [...];
const columns: readonly Column<Row>[] = [
{
key: 'name',
name: 'Name',
sortable: true
},
];
function MyGrid() {
const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([]);
return (
<DataGrid
columns={columns}
rows={rows}
sortColumns={sortColumns}
onSortColumnsChange={setSortColumns}
/>
);
}
Grid can be sorted on multiple columns using ctrl (command) + click
. To disable multiple column sorting, change the onSortColumnsChange
function to
onSortColumnsChange(sortColumns: SortColumn[]) {
setSortColumns(sortColumns.slice(-1));
}
defaultColumnOptions?: Maybe<DefaultColumnOptions<R, SR>>
Default options applied to all columns.
function MyGrid() {
return (
<DataGrid
columns={columns}
rows={rows}
defaultColumnOptions={{
minWidth: 100,
resizable: true,
sortable: true,
draggable: true
}}
/>
);
}
onFill?: Maybe<(event: FillEvent<R>) => R>
onCellClick?: Maybe<(args: CellClickArgs<R, SR>, event: CellMouseEvent) => void>
Callback triggered when a cell is clicked. The default behavior is to select the cell. Call preventGridDefault
to prevent the default behavior
function onCellClick(args: CellClickArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
event.preventGridDefault();
}
}
<DataGrid rows={rows} columns={columns} onCellClick={onCellClick} />;
This event can be used to open cell editor on single click
function onCellClick(args: CellClickArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
event.preventGridDefault();
args.selectCell(true);
}
}
Arguments:
args: CellClickArgs<R, SR>
args.rowIdx
: number
- row index of the currently selected cell
args.row
: R
- row object of the currently selected cell
args.column
: CalculatedColumn<TRow, TSummaryRow>
- column object of the currently selected cell
args.selectCell
: (enableEditor?: boolean) => void
- function to manually select the cell and optionally pass true
to start editing
event
extends React.MouseEvent<HTMLDivElement>
event.preventGridDefault:
: () => void
event.isGridDefaultPrevented
: boolean
onCellDoubleClick?: Maybe<(args: CellClickArgs<R, SR>, event: CellMouseEvent) => void>
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
function onCellDoubleClick(args: CellClickArgs<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. The default behavior is to select the cell. Call preventGridDefault
to prevent the default behavior
function onCellContextMenu(args: CellClickArgs<R, SR>, event: CellMouseEvent) {
if (args.column.key === 'id') {
event.preventGridDefault();
}
}
<DataGrid rows={rows} columns={columns} onCellContextMenu={onCellContextMenu} />;
onCellKeyDown?: Maybe<(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) => void>
A function called when keydown event is triggered on a cell. This event can be used to customize cell navigation and editing behavior.
Examples
function onCellKeyDown(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) {
if (args.mode === 'SELECT' && event.key === 'Enter') {
event.preventGridDefault();
}
}
- Prevent navigation on
Tab
function onCellKeyDown(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) {
if (args.mode === 'SELECT' && event.key === 'Tab') {
event.preventGridDefault();
}
}
Check more examples
onCellCopy?: Maybe<(args: CellCopyEvent<NoInfer<R>, NoInfer<SR>>, event: CellClipboardEvent) => void>
Callback triggered when a cell's content is copied.
onCellPaste?: Maybe<(args: CellPasteEvent<NoInfer<R>, NoInfer<SR>>, event: CellClipboardEvent) => void>
Callback triggered when content is pasted into a cell.
onSelectedCellChange?: Maybe<(args: CellSelectArgs<R, SR>) => void>;
Triggered when the selected cell is changed.
Arguments:
args.rowIdx
: number
- row index
args.row
: R
- row object of the currently selected cell
args.column
: CalculatedColumn<TRow, TSummaryRow>
- column object of the currently selected cell
onScroll?: Maybe<(event: React.UIEvent<HTMLDivElement>) => void>
Callback triggered when the grid is scrolled.
onColumnResize?: Maybe<(column: CalculatedColumn<R, SR>, width: number) => void>
Callback triggered when column is resized.
onColumnsReorder?: Maybe<(sourceColumnKey: string, targetColumnKey: string) => void>
Callback triggered when columns are reordered.
enableVirtualization?: Maybe<boolean>
Default: true
This prop can be used to disable virtualization.
renderers?: Maybe<Renderers<R, SR>>
Custom renderers for cells, rows, and other components.
interface Renderers<TRow, TSummaryRow> {
renderCell?: Maybe<(key: Key, props: CellRendererProps<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>;
}
For example, the default <Row />
component can be wrapped via the renderRow
prop to add contexts or tweak props
import { DataGrid, RenderRowProps, Row } from 'react-data-grid';
function myRowRenderer(key: React.Key, props: RenderRowProps<Row>) {
return (
<MyContext key={key} value={123}>
<Row {...props} />
</MyContext>
);
}
function MyGrid() {
return <DataGrid columns={columns} rows={rows} renderers={{ renderRow: myRowRenderer }} />;
}
:warning: To prevent all rows from being unmounted on re-renders, make sure to pass a static or memoized component to renderRow
.
rowClass?: Maybe<(row: R, rowIdx: number) => Maybe<string>>
Function to apply custom class names to rows.
import { DataGrid } from 'react-data-grid';
function MyGrid() {
return <DataGrid columns={columns} rows={rows} rowClass={rowClass} />;
}
function rowClass(row: Row, rowIdx: number) {
return rowIdx % 2 === 0 ? 'even' : 'odd';
}
Custom class name for the header row.
direction?: Maybe<'ltr' | 'rtl'>
This property sets the text direction of the grid, it defaults to 'ltr'
(left-to-right). Setting direction
to 'rtl'
has the following effects:
- Columns flow from right to left
- Frozen columns are pinned on the right
- Column resize handle is shown on the left edge of the column
- Scrollbar is moved to the left
className?: string | undefined
Custom class name for the grid.
style?: CSSProperties | undefined
Custom styles for the grid.
'aria-label'?: string | undefined
The label of the grid. We recommend providing a label using aria-label
or aria-labelledby
'aria-labelledby'?: string | undefined
The id of the element containing a label for the grid. We recommend providing a label using aria-label
or aria-labelledby
'aria-description'?: string | undefined
'aria-describedby'?: string | undefined
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.
'data-testid'?: Maybe<string>
This prop can be used to add a testid for testing. We recommend using role
and name
to find the grid element
function MyGrid() {
return <DataGrid aria-label="my-grid" columns={columns} rows={rows} />;
}
function MyGridTest() {
const grid = screen.getByRole('grid', { name: 'my-grid' });
}
<TreeDataGrid />
TreeDataGrid
is component built on top of DataGrid
to add row grouping. This implements the Treegrid pattern. At the moment TreeDataGrid
does not support onFill
and isRowSelectionDisabled
props
TreeDataGridProps
groupBy?: Maybe<readonly string[]>
rowGrouper?: Maybe<(rows: readonly R[], columnKey: string) => Record<string, readonly R[]>>
expandedGroupIds?: Maybe<ReadonlySet<unknown>>
onExpandedGroupIdsChange?: Maybe<(expandedGroupIds: Set<unknown>) => void>
groupIdGetter?: Maybe<(groupKey: string, parentId?: string) => string>
<TextEditor />
Props
See RenderEditCellProps
<Row />
See renderers
Props
See RenderRowProps
The ref
prop is supported.
Props
onSort: (ctrlClick: boolean) => void
sortDirection: SortDirection | undefined
priority: number | undefined
tabIndex: number
children: React.ReactNode
<ValueFormatter />
Props
See FormatterProps
<SelectCellFormatter />
Props
value: boolean
tabIndex: number
disabled?: boolean | undefined
onChange: (value: boolean, isShiftClick: boolean) => void
onClick?: MouseEventHandler<T> | undefined
'aria-label'?: string | undefined
'aria-labelledby'?: string | undefined
<ToggleGroupFormatter />
Props
See RenderGroupCellProps
Hooks
useRowSelection<R>(): { isRowSelectionDisabled, isRowSelected, onRowSelectionChange }
Other
SelectColumn: Column<any, any>
SELECT_COLUMN_KEY = 'rdg-select-column'
Types
Column
name: string | ReactElement
The name of the column. Displayed in the header cell by default.
key: string
A unique key to distinguish each column
width?: Maybe<number | string>
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.
width: 80;
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.
minWidth?: Maybe<number>
Default: 50
pixels
Minimum column width in pixels.
maxWidth?: Maybe<number>
Maximum column width in pixels.
cellClass?: Maybe<string | ((row: TRow) => Maybe<string>)>
Class name(s) for the cell
Class name(s) for the header cell.
summaryCellClass?: Maybe<string | ((row: TSummaryRow) => Maybe<string>)>
Class name(s) for the summary cell.
renderCell?: Maybe<(props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>
Render function to render the content of cells.
Render function to render the content of the header cell.
renderSummaryCell?: Maybe<(props: RenderSummaryCellProps<TSummaryRow, TRow>) => ReactNode>
Render function to render the content of summary cells
renderEditCell?: Maybe<(props: RenderEditCellProps<TRow, TSummaryRow>) => ReactNode>
Render function to render the content of edit cells. When set, the column is automatically set to be editable
editable?: Maybe<boolean | ((row: TRow) => boolean)>
Enables cell editing. If set and no editor property specified, then a textinput will be used as the cell editor.
colSpan?: Maybe<(args: ColSpanArgs<TRow, TSummaryRow>) => Maybe<number>>
frozen?: Maybe<boolean>
Default: false
Determines whether column is frozen. Frozen columns are pinned on the left. At the moment we do not support pinning columns on the right.
resizable?: Maybe<boolean>
Default: false
Enable resizing of the column
sortable?: Maybe<boolean>
Default: false
Enable sorting of the column
draggable?: Maybe<boolean>
Default: false
Enable dragging of the column
sortDescendingFirst?: Maybe<boolean>
Default: false
Sets the column sort order to be descending instead of ascending the first time the column is sorted
editorOptions
Options for cell editing.
displayCellContent?: Maybe<boolean>
Default: false
Render the cell content in addition to the edit cell. Enable this option when the editor is rendered outside the grid, like a modal for example.
commitOnOutsideClick?: Maybe<boolean>
Default: true
Commit changes when clicking outside the cell.
closeOnExternalRowChange?: Maybe<boolean>
Default: true
Close the editor when the row changes externally.
DataGridHandle
RenderEditCellProps
RenderCellProps
RenderGroupCellProps
RenderRowProps
Generics
R
, TRow
: Row type
SR
, TSummaryRow
: Summary row type
K
: Row key type