Comcast/react-data-grid(新しいタブで開きます)
主要言語: TypeScript
Feature-rich and customizable data grid React component
- star 数
- 7,693
- watcher 数
- 131
- fork 数
- 2,206
- issue 数
- 79
- 最終更新
- 2026/10/31
主要言語: TypeScript
Feature-rich and customizable data grid React component
The DataGrid component is designed to handle large datasets efficiently while offering a rich set of features for customization and interactivity.
color-schemeInstall 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-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.
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} />
In forced colors mode, such as Windows contrast themes, the DataGrid uses system colors for the active cell, row selection, and the drag handle, so they follow the user's palette. Overriding --rdg-selection-color or --rdg-checkbox-focus-color in your own styles also overrides their forced colors values outside selected rows, so wrap such overrides in @media not (forced-colors: active).
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.
Ctrl also accepts ⌘, as macOS uses Ctrl+←/→ to switch desktops. In right-to-left grids, ← and → are swapped. See onCellKeyDown to customize them.
| Keys | Action |
|---|---|
| ← → ↑ ↓ | Move to the adjacent cell |
| Tab / Shift+Tab | Move to the next or previous cell. Focus leaves the grid from the last or first cell |
| Home / End | Move to the first or last cell of the row |
| Ctrl+Home / Ctrl+End | Move to the first header cell or the last cell of the last row |
| Page Up / Page Down | Move up or down by one page of rows |
| Keys | Action |
|---|---|
| Typing or Enter | Open the editor |
| Enter / Escape | Commit or discard the changes and close the editor |
| Tab / Shift+Tab | Commit the changes and move to the next or previous cell |
| Ctrl+C / Ctrl+V | Copy or paste, with onCellCopy and onCellPaste |
| Keys | Action |
|---|---|
| Shift+Space | Select or deselect the row of the active cell |
| Keys | Action |
|---|---|
| Enter / Space | Sort by the column |
| Ctrl+Enter / Ctrl+Space | Add the column to the sort, keeping the other sorted columns |
| Ctrl+← / Ctrl+→ | Resize the column |
See TreeDataGrid for the keys that expand and collapse groups.
An array of column definitions and/or column groups. See the ColumnOrColumnGroup type for all available options.
⚠️ Performance: Passing a new 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.
⚠️ Performance: Memoize this array to prevent internal memoization invalidation.
Rows pinned at the bottom of the grid for summary purposes.
⚠️ Performance: Memoize this array to prevent internal memoization invalidation.
Function to get a unique key for each row. Required for row selection.
import { DataGrid } from 'react-data-grid'; interface Row { id: number; name: string; } function getRowKey(row: Row) { return row.id; } function MyGrid() { return <DataGrid columns={columns} rows={rows} getRowKey={getRowKey} />; }
💡 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.
⚠️ Performance: Define this function outside your component or memoize it with 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} />;
⚠️ Performance: When using a function, the heights of all rows are processed upfront. For large datasets (1000+ rows), this can cause performance issues if the identity of the function changes and invalidates internal memoization. Consider using a static function when possible, or memoize the 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. getRowKey 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 getRowKey(row: Row) { return row.id; } function isRowSelectionDisabled(row: Row) { return !row.isActive; } function MyGrid() { const [selectedRows, setSelectedRows] = useState((): ReadonlySet<number> => new Set()); return ( <DataGrid getRowKey={getRowKey} 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.
It is not called for keydown events triggered in a :modal editor, see renderEditCell.
Examples
Enterfunction onCellKeyDown(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) { if (args.mode === 'ACTIVE' && event.key === 'Enter') { event.preventGridDefault(); } }
Tabfunction 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} />; }
⚠️ Performance: Define this function outside your component or memoize it with 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:
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:
groupBy prop specifies which columns should be used for groupinggetRowGroupKey when providedKeyboard Navigation:
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 - TreeDataGrid manages the ARIA rolearia-rowcount - TreeDataGrid manages the ARIA row countCaveats:
columns must be Column[]Group rows in callbacks:
Callbacks that receive the active row receive group rows too: onCellKeyDown and onActivePositionChange. Their arguments are typed with TreeCellKeyDownArgs and TreePositionChangeArgs; use isGroupRow to tell group rows apart from regular rows.
import { isGroupRow, type CellKeyboardEvent, type TreeCellKeyDownArgs } from 'react-data-grid'; function onCellKeyDown(args: TreeCellKeyDownArgs<Row>, event: CellKeyboardEvent) { if (args.mode !== 'ACTIVE') return; if (isGroupRow(args.row)) { console.log(`Group ${args.row.groupKey} with ${args.row.childRows.length} rows`); return; } console.log(args.row.name); }
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, and onCellKeyDown and onActivePositionChange receive group rows too. 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' } ]; const groupBy = ['country', 'city']; function MyGrid() { return ( <TreeDataGrid columns={columns} rows={rows} groupBy={groupBy} // ... other props /> ); }
⚠️ Performance: Define this array outside your component or memoize it with useMemo, otherwise all the rows are grouped again on every render.
Required. A set of group IDs that are currently expanded. Group IDs are generated by getGroupId.
import { useState } from 'react'; import { TreeDataGrid } from 'react-data-grid'; function MyGrid() { const [expandedGroupIds, setExpandedGroupIds] = useState((): ReadonlySet<string> => new Set()); return ( <TreeDataGrid expandedGroupIds={expandedGroupIds} onExpandedGroupIdsChange={setExpandedGroupIds} // ... other props /> ); }
Required. Callback triggered when groups are expanded or collapsed.
A function that returns the key of the group a row belongs to, for the specified column key. Rows sharing the same group key are grouped together, and groups are ordered by the first row that belongs to them. If not provided, a default implementation is used that stringifies the row's value for that column, i.e., String(row[columnKey]).
Provide your own to group on something other than the raw cell value:
function getRowGroupKey(row: Row, columnKey: string): string { if (columnKey === 'date') { return row.date.getFullYear().toString(); } return String(row[columnKey]); }
⚠️ Performance: Define this function outside your component or memoize it with useCallback, otherwise all the rows are grouped again on every render.
Function to generate unique IDs for group rows. If not provided, a default implementation is used that concatenates parent and group keys with __.
⚠️ Performance: Define this function outside your component or memoize it 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} ... />
Callback triggered when a key is pressed in a cell or a row, including group rows. Unlike DataGrid, the active row in ACTIVE mode can be a group row: use isGroupRow to narrow it. See the TreeCellKeyDownArgs type and the onCellKeyDown prop on <DataGrid />.
Callback triggered when the active position changes, including to a group row or a cell of one: use isGroupRow to narrow the row. See the TreePositionChangeArgs type.
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 checkbox