From b21706cb79acf62b83479c414db70e165ff4d396 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Tue, 28 Oct 2025 17:20:13 +0000 Subject: [PATCH 01/17] Documentation --- README.md | 936 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 884 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 767c603769..440ef19267 100644 --- a/README.md +++ b/README.md @@ -134,9 +134,7 @@ Set `--rdg-color-scheme: light/dark` at the `:root` to control the color theme. ###### `columns: readonly Column[]` -See [`Column`](#column). - -An array of column definitions. Each column should have a key and name. +An array of column definitions. Each column should have a key and name. See the [`Column`](#columntrow-tsummaryrow) type for all available options. :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. @@ -360,8 +358,6 @@ function onCellMouseDown(args: CellMouseDownArgs, event: CellMouseEvent) ; ``` -See [`CellMouseArgs`](#cellmouseargs) and [`CellMouseEvent`](#cellmouseevent) - ###### `onCellClick?: Maybe<(args: CellMouseArgs, event: CellMouseEvent) => void>` Callback triggered when a cell is clicked. @@ -386,8 +382,6 @@ function onCellClick(args: CellMouseArgs, event: CellMouseEvent) { } ``` -See [`CellMouseArgs`](#cellmouseargs) and [`CellMouseEvent`](#cellmouseevent) - ###### `onCellDoubleClick?: Maybe<(args: CellMouseArgs, 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. @@ -402,8 +396,6 @@ function onCellDoubleClick(args: CellMouseArgs, event: CellMouseEvent) { ; ``` -See [`CellMouseArgs`](#cellmouseargs) and [`CellMouseEvent`](#cellmouseevent) - ###### `onCellContextMenu?: Maybe<(args: CellMouseArgs, event: CellMouseEvent) => void>` Callback triggered when a cell is right-clicked. @@ -419,8 +411,6 @@ function onCellContextMenu(args: CellMouseArgs, event: CellMouseEvent) { ; ``` -See [`CellMouseArgs`](#cellmouseargs) and [`CellMouseEvent`](#cellmouseevent) - ###### `onCellKeyDown?: Maybe<(args: CellKeyDownArgs, 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. @@ -601,81 +591,304 @@ test('grid', async () => { ###### `groupIdGetter?: Maybe<(groupKey: string, parentId?: string) => string>` -#### `` +#### `textEditor` -##### Props +The default text editor component for editing cells. -See [`RenderEditCellProps`](#rendereditcellprops) +##### Props -#### `` +`RenderEditCellProps` - See the Types section below. -See [`renderers`](#renderers-mayberenderersr-sr) +**Example:** -##### Props +```tsx +import { textEditor } from 'react-data-grid'; -See [`RenderRowProps`](#renderrowprops) +const columns: Column[] = [ + { + key: 'title', + name: 'Title', + renderEditCell: textEditor + } +]; +``` -The `ref` prop is supported. +#### `` -#### `` +The default row component. Can be wrapped via the `renderers.renderRow` prop. ##### Props -###### `onSort: (ctrlClick: boolean) => void` - -###### `sortDirection: SortDirection | undefined` - -###### `priority: number | undefined` +`RenderRowProps` - See the Types section below. -###### `tabIndex: number` +The `ref` prop is supported. -###### `children: React.ReactNode` +#### `` -#### `` +The default cell component. Can be wrapped via the `renderers.renderCell` prop. ##### Props -See [`RenderCellProps`](#rendercellprops) +`CellRendererProps` - See the Types section below. #### `` +A formatter component for rendering selection checkboxes. + ##### Props ###### `value: boolean` +Whether the checkbox is checked. + ###### `tabIndex: number` +The tab index for keyboard navigation. + ###### `disabled?: boolean | undefined` +Whether the checkbox is disabled. + ###### `onChange: (value: boolean, isShiftClick: boolean) => void` +Callback when the checkbox state changes. + ###### `onClick?: MouseEventHandler | undefined` +Optional click handler. + ###### `'aria-label'?: string | undefined` +Accessible label for the checkbox. + ###### `'aria-labelledby'?: string | undefined` -#### `` +ID of the element that labels the checkbox. + +### Hooks + +#### `useHeaderRowSelection(): { isIndeterminate: boolean, isRowSelected: boolean, onRowSelectionChange: (event: SelectHeaderRowEvent) => void }` + +Hook for managing header row selection state. Used within custom header cell renderers to implement "select all" functionality. + +**Returns:** + +- `isIndeterminate`: Whether some (but not all) rows are selected +- `isRowSelected`: Whether all rows are selected +- `onRowSelectionChange`: Callback to change selection state + +**Example:** + +```tsx +function CustomHeaderCell() { + const { isIndeterminate, isRowSelected, onRowSelectionChange } = useHeaderRowSelection(); + + return ( + onRowSelectionChange({ checked: e.target.checked })} + /> + ); +} +``` + +#### `useRowSelection(): { isRowSelectionDisabled: boolean, isRowSelected: boolean, onRowSelectionChange: (event: SelectRowEvent) => void }` + +Hook for managing row selection state. Used within custom cell renderers to implement row selection. + +**Returns:** + +- `isRowSelectionDisabled`: Whether selection is disabled for this row +- `isRowSelected`: Whether this row is selected +- `onRowSelectionChange`: Callback to change selection state + +**Example:** + +```tsx +function CustomSelectCell({ row }: RenderCellProps) { + const { isRowSelectionDisabled, isRowSelected, onRowSelectionChange } = useRowSelection(); + + return ( + + onRowSelectionChange({ + row, + checked: e.target.checked, + isShiftClick: e.nativeEvent.shiftKey + }) + } + /> + ); +} +``` + +### Render Functions + +#### `renderHeaderCell(props: RenderHeaderCellProps): ReactNode` + +The default header cell renderer. Renders sortable columns with sort indicators. + +**Example:** + +```tsx +import { renderHeaderCell } from 'react-data-grid'; + +const columns: Column[] = [ + { + key: 'name', + name: 'Name', + sortable: true, + renderHeaderCell + } +]; +``` + +#### `renderSortIcon(props: RenderSortIconProps): ReactNode` + +Renders the sort direction arrow icon. + +**Props:** + +- `sortDirection: SortDirection | undefined` - 'ASC', 'DESC', or undefined + +#### `renderSortPriority(props: RenderSortPriorityProps): ReactNode` + +Renders the sort priority number for multi-column sorting. + +**Props:** + +- `priority: number | undefined` - The sort priority (1, 2, 3, etc.) + +#### `renderCheckbox(props: RenderCheckboxProps): ReactNode` + +Renders a checkbox input with proper styling and accessibility. + +**Props:** + +- `checked: boolean` - Whether the checkbox is checked +- `indeterminate?: boolean` - Whether the checkbox is in indeterminate state +- `disabled?: boolean` - Whether the checkbox is disabled +- `onChange: (checked: boolean, shift: boolean) => void` - Change handler +- `tabIndex: number` - Tab index for keyboard navigation +- `aria-label?: string` - Accessible label +- `aria-labelledby?: string` - ID of labeling element + +**Example:** + +```tsx +import { renderCheckbox } from 'react-data-grid'; + +const renderers = { + renderCheckbox: (props) => renderCheckbox({ ...props, 'aria-label': 'Select row' }) +}; +``` + +#### `renderToggleGroup(props: RenderGroupCellProps): ReactNode` + +Renders the expand/collapse toggle for grouped rows. ##### Props -See [`RenderGroupCellProps`](#rendergroupcellprops) +`RenderGroupCellProps` - See the Types section below. -### Hooks +**Example:** + +```tsx +import { renderToggleGroup } from 'react-data-grid'; + +const columns: Column[] = [ + { + key: 'group', + name: 'Group', + renderGroupCell: renderToggleGroup + } +]; +``` + +#### `renderValue(props: RenderCellProps): ReactNode` + +A simple cell renderer that displays the cell value as text. -#### `useHeaderRowSelection(): { isIndeterminate, isRowSelected, onRowSelectionChange }` +**Example:** + +```tsx +import { renderValue } from 'react-data-grid'; + +const columns: Column[] = [ + { + key: 'title', + name: 'Title', + renderCell: renderValue + } +]; +``` + +### Context + +#### `DataGridDefaultRenderersContext` + +Context for providing default renderers to the DataGrid. Used internally but can be useful for deeply nested custom components that need access to default renderers. + +**Example:** + +```tsx +import { DataGridDefaultRenderersContext } from 'react-data-grid'; +import { useContext } from 'react'; -#### `useRowSelection(): { isRowSelectionDisabled, isRowSelected, onRowSelectionChange }` +function CustomComponent() { + const renderers = useContext(DataGridDefaultRenderersContext); + return renderers?.renderCheckbox?.({ ... }); +} +``` ### Other #### `SelectColumn: Column` +A pre-configured column for row selection. Includes checkbox renderers for header, regular rows, and grouped rows. + +**Example:** + +```tsx +import { DataGrid, SelectColumn } from 'react-data-grid'; + +const columns = [SelectColumn, ...otherColumns]; + +function MyGrid() { + return ( + row.id} + selectedRows={selectedRows} + onSelectedRowsChange={setSelectedRows} + /> + ); +} +``` + #### `SELECT_COLUMN_KEY = 'rdg-select-column'` +The key used for the `SelectColumn`. Useful for identifying or filtering the select column. + +**Example:** + +```tsx +import { SELECT_COLUMN_KEY } from 'react-data-grid'; + +const nonSelectColumns = columns.filter((col) => col.key !== SELECT_COLUMN_KEY); +``` + ### Types -#### `Column` +#### `Column` + +Defines the configuration for a column in the grid. ##### `name: string | ReactElement` @@ -712,7 +925,7 @@ Maximum column width in pixels. ##### `cellClass?: Maybe Maybe)>` -Class name(s) for the cell +Class name(s) for the cell. Can be a string or a function that returns a class name based on the row. ##### `headerCellClass?: Maybe` @@ -720,7 +933,7 @@ Class name(s) for the header cell. ##### `summaryCellClass?: Maybe Maybe)>` -Class name(s) for the summary cell. +Class name(s) for the summary cell. Can be a string or a function that returns a class name based on the summary row. ##### `renderCell?: Maybe<(props: RenderCellProps) => ReactNode>` @@ -734,6 +947,10 @@ Render function to render the content of the header cell. Render function to render the content of summary cells +##### `renderGroupCell?: Maybe<(props: RenderGroupCellProps) => ReactNode>` + +Render function to render the content of group cells when using `TreeDataGrid`. + ##### `renderEditCell?: Maybe<(props: RenderEditCellProps) => ReactNode>` Render function to render the content of edit cells. When set, the column is automatically set to be editable @@ -742,7 +959,26 @@ Render function to render the content of edit cells. When set, the column is aut Enables cell editing. If set and no editor property specified, then a text input will be used as the cell editor. -##### `colSpan?: Maybe<(args: ColSpanArgs) => Maybe>` +##### `colSpan?: Maybe<(args: ColSpanArgs) => Maybe>` + +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 in the Types section below. + +**Example:** + +```tsx +const columns: Column[] = [ + { + key: 'title', + name: 'Title', + colSpan(args) { + if (args.type === 'ROW' && args.row.isFullWidth) { + return 5; // Span 5 columns for full-width rows + } + return undefined; + } + } +]; +``` ##### `frozen?: Maybe` @@ -796,41 +1032,637 @@ Commit changes when clicking outside the cell. Close the editor when the row changes externally. -#### `CellMouseArgs` +#### `CalculatedColumn` -##### `rowIdx: number` +Extends `Column` with additional computed properties used internally by the grid. This is the type passed to render functions. -Row index of the currently selected cell +**Additional properties:** -##### `row: TRow` +- `idx: number` - The column index +- `level: number` - Nesting level when using column groups +- `parent: CalculatedColumnParent | undefined` - Parent column group if nested +- All optional Column properties become required with default values + +#### `CalculatedColumnParent` + +Represents a parent column group in the calculated column structure. + +```tsx +interface CalculatedColumnParent { + readonly name: string | ReactElement; + readonly parent: CalculatedColumnParent | undefined; + readonly idx: number; + readonly colSpan: number; + readonly level: number; + readonly headerCellClass?: Maybe; +} +``` + +#### `CalculatedColumnOrColumnGroup` + +Union type representing either a `CalculatedColumnParent` or a `CalculatedColumn`. + +```tsx +type CalculatedColumnOrColumnGroup = CalculatedColumnParent | CalculatedColumn; +``` + +#### `ColumnGroup` + +Defines a group of columns that share a common header. + +```tsx +interface ColumnGroup { + readonly name: string | ReactElement; + readonly headerCellClass?: Maybe; + readonly children: readonly ColumnOrColumnGroup[]; +} +``` + +**Example:** + +```tsx +const columns = [ + { + name: 'Personal Info', + children: [ + { key: 'firstName', name: 'First Name' }, + { key: 'lastName', name: 'Last Name' } + ] + } +]; +``` + +#### `ColumnOrColumnGroup` + +Union type representing either a `Column` or a `ColumnGroup`. + +#### `RowHeightArgs` + +Arguments passed to the `rowHeight` function when it's a function. + +```tsx +type RowHeightArgs = { type: 'ROW'; row: TRow } | { type: 'GROUP'; row: GroupRow }; +``` + +**Example:** + +```tsx +function getRowHeight(args: RowHeightArgs): number { + if (args.type === 'GROUP') { + return 40; + } + return args.row.isLarge ? 60 : 35; +} + + +``` + +#### `RenderCellProps` + +Props passed to custom cell renderers. + +```tsx +interface RenderCellProps { + column: CalculatedColumn; + row: TRow; + rowIdx: number; + isCellEditable: boolean; + tabIndex: number; + onRowChange: (row: TRow) => void; +} +``` + +**Example:** + +```tsx +function CustomCell({ row, column, onRowChange }: RenderCellProps) { + return ( +
+ {row[column.key]} + +
+ ); +} +``` + +#### `RenderHeaderCellProps` + +Props passed to custom header cell renderers. + +```tsx +interface RenderHeaderCellProps { + column: CalculatedColumn; + sortDirection: SortDirection | undefined; + priority: number | undefined; + tabIndex: number; +} +``` + +#### `RenderEditCellProps` + +Props passed to custom edit cell renderers (editors). + +```tsx +interface RenderEditCellProps { + column: CalculatedColumn; + row: TRow; + rowIdx: number; + onRowChange: (row: TRow, commitChanges?: boolean) => void; + onClose: (commitChanges?: boolean, shouldFocusCell?: boolean) => void; +} +``` + +**Example:** + +```tsx +function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps) { + return ( + onRowChange({ ...row, [column.key]: e.target.value })} + onBlur={() => onClose(true)} + /> + ); +} +``` + +#### `RenderSummaryCellProps` + +Props passed to summary cell renderers. + +```tsx +interface RenderSummaryCellProps { + column: CalculatedColumn; + row: TSummaryRow; + tabIndex: number; +} +``` + +#### `RenderGroupCellProps` + +Props passed to group cell renderers when using `TreeDataGrid`. + +```tsx +interface RenderGroupCellProps { + groupKey: unknown; + column: CalculatedColumn; + row: GroupRow; + childRows: readonly TRow[]; + isExpanded: boolean; + tabIndex: number; + toggleGroup: () => void; +} +``` + +#### `RenderRowProps` + +Props passed to custom row renderers. + +```tsx +interface RenderRowProps { + row: TRow; + viewportColumns: readonly CalculatedColumn[]; + rowIdx: number; + selectedCellIdx: number | undefined; + isRowSelected: boolean; + isRowSelectionDisabled: boolean; + gridRowStart: number; + lastFrozenColumnIndex: number; + draggedOverCellIdx: number | undefined; + selectedCellEditor: ReactElement> | undefined; + onRowChange: (column: CalculatedColumn, rowIdx: number, newRow: TRow) => void; + rowClass: Maybe<(row: TRow, rowIdx: number) => Maybe>; + // ... and event handlers +} +``` -row object of the currently selected cell +#### `CellRendererProps` + +Props passed to the cell renderer when using `renderers.renderCell`. + +Extends `RenderRowProps` with cell-specific properties like `column`, `colSpan`, `isCellSelected`, etc. + +#### `Renderers` + +Custom renderer configuration for the grid. + +```tsx +interface Renderers { + renderCell?: Maybe<(key: Key, props: CellRendererProps) => ReactNode>; + renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>; + renderRow?: Maybe<(key: Key, props: RenderRowProps) => ReactNode>; + renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>; + noRowsFallback?: Maybe; +} +``` + +#### `CellMouseArgs` + +Arguments passed to cell mouse event handlers. + +```tsx +interface CellMouseArgs { + column: CalculatedColumn; + row: TRow; + rowIdx: number; + selectCell: (enableEditor?: boolean) => void; +} +``` ##### `column: CalculatedColumn` -column object of the currently selected cell +The column object of the cell. + +##### `row: TRow` + +The row object of the cell. + +##### `rowIdx: number` + +The row index of the cell. ##### `selectCell: (enableEditor?: boolean) => void` -function to manually select the cell and optionally pass `true` to start editing +Function to manually select the cell. Pass `true` to immediately start editing. + +**Example:** + +```tsx +function onCellClick(args: CellMouseArgs, event: CellMouseEvent) { + console.log('Clicked cell at row', args.rowIdx, 'column', args.column.key); + args.selectCell(true); // Select and start editing +} +``` #### `CellMouseEvent` -Extends `React.MouseEvent` +Extends `React.MouseEvent` with grid-specific methods. + +##### `event.preventGridDefault(): void` + +Prevents the default grid behavior for this event. + +##### `event.isGridDefaultPrevented(): boolean` + +Returns whether `preventGridDefault` was called. + +**Example:** + +```tsx +function onCellClick(args: CellMouseArgs, event: CellMouseEvent) { + if (args.column.key === 'actions') { + event.preventGridDefault(); // Prevent cell selection + } +} +``` + +#### `CellKeyboardEvent` + +Extends `React.KeyboardEvent` with grid-specific methods. + +##### `event.preventGridDefault(): void` + +Prevents the default grid behavior for this keyboard event. + +##### `event.isGridDefaultPrevented(): boolean` + +Returns whether `preventGridDefault` was called. + +#### `CellClipboardEvent` + +Type alias for `React.ClipboardEvent`. Used for copy and paste events. + +```tsx +type CellClipboardEvent = React.ClipboardEvent; +``` + +#### `CellKeyDownArgs` + +Arguments passed to the `onCellKeyDown` handler. The shape differs based on whether the cell is in SELECT or EDIT mode. + +**SELECT mode:** + +```tsx +interface SelectCellKeyDownArgs { + mode: 'SELECT'; + column: CalculatedColumn; + row: TRow; + rowIdx: number; + selectCell: (position: Position, options?: SelectCellOptions) => void; +} +``` + +**EDIT mode:** + +```tsx +interface EditCellKeyDownArgs { + mode: 'EDIT'; + column: CalculatedColumn; + row: TRow; + rowIdx: number; + navigate: () => void; + onClose: (commitChanges?: boolean, shouldFocusCell?: boolean) => void; +} +``` + +**Example:** + +```tsx +function onCellKeyDown(args: CellKeyDownArgs, event: CellKeyboardEvent) { + if (args.mode === 'EDIT' && event.key === 'Escape') { + args.onClose(false); // Close without committing + event.preventGridDefault(); + } +} +``` + +#### `CellSelectArgs` + +Arguments passed to `onSelectedCellChange`. + +```tsx +interface CellSelectArgs { + rowIdx: number; + row: TRow | undefined; + column: CalculatedColumn; +} +``` + +#### `CellCopyArgs` + +Arguments passed to `onCellCopy`. + +```tsx +interface CellCopyArgs { + column: CalculatedColumn; + row: TRow; +} +``` + +#### `CellPasteArgs` + +Arguments passed to `onCellPaste`. + +```tsx +interface CellPasteArgs { + column: CalculatedColumn; + row: TRow; +} +``` + +#### `ColSpanArgs` + +Arguments passed to the `colSpan` function. + +```tsx +type ColSpanArgs = + | { type: 'HEADER' } + | { type: 'ROW'; row: TRow } + | { type: 'SUMMARY'; row: TSummaryRow }; +``` + +**Example:** + +```tsx +const columns: Column[] = [ + { + key: 'title', + name: 'Title', + colSpan(args) { + if (args.type === 'ROW' && args.row.isFullWidth) { + return 3; // Span 3 columns + } + return undefined; + } + } +]; +``` + +#### `SortColumn` + +Describes a sorted column. + +```tsx +interface SortColumn { + readonly columnKey: string; + readonly direction: SortDirection; +} +``` + +#### `SortDirection` + +```tsx +type SortDirection = 'ASC' | 'DESC'; +``` + +#### `RowsChangeData` + +Data provided to `onRowsChange` callback. + +```tsx +interface RowsChangeData { + indexes: number[]; + column: CalculatedColumn; +} +``` + +- `indexes`: Array of row indexes that changed +- `column`: The column where changes occurred + +#### `SelectRowEvent` + +Event object for row selection changes. + +```tsx +interface SelectRowEvent { + row: TRow; + checked: boolean; + isShiftClick: boolean; +} +``` + +#### `SelectHeaderRowEvent` + +Event object for header row selection changes. + +```tsx +interface SelectHeaderRowEvent { + checked: boolean; +} +``` + +#### `FillEvent` + +Event object for drag-fill operations. + +```tsx +interface FillEvent { + columnKey: string; + sourceRow: TRow; + targetRow: TRow; +} +``` + +Used with the `onFill` prop to handle cell value dragging. + +#### `GroupRow` + +Represents a grouped row in `TreeDataGrid`. + +```tsx +interface GroupRow { + 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; +} +``` + +#### `ColumnWidths` + +A map of column widths. + +```tsx +type ColumnWidths = ReadonlyMap; + +interface ColumnWidth { + readonly type: 'resized' | 'measured'; + readonly width: number; +} +``` + +Used with `columnWidths` and `onColumnWidthsChange` props to control column widths externally. + +#### `Position` + +Represents a cell position in the grid. + +```tsx +interface Position { + readonly idx: number; // Column index + readonly rowIdx: number; // Row index +} +``` + +#### `SelectCellOptions` + +Options for programmatically selecting a cell. + +```tsx +interface SelectCellOptions { + enableEditor?: Maybe; + shouldFocusCell?: Maybe; +} +``` -##### `event.preventGridDefault: () => void` +#### `RenderCheckboxProps` -##### `event.isGridDefaultPrevented: boolean` +Props for custom checkbox renderers. + +```tsx +interface RenderCheckboxProps { + checked: boolean; + indeterminate?: boolean; + disabled?: boolean; + onChange: (checked: boolean, shift: boolean) => void; + tabIndex: number; + 'aria-label'?: string; + 'aria-labelledby'?: string; +} +``` + +#### `RenderSortStatusProps` + +Props for custom sort status renderers. + +```tsx +interface RenderSortStatusProps { + sortDirection: SortDirection | undefined; + priority: number | undefined; +} +``` + +#### `RenderSortIconProps` + +Props for custom sort icon renderers. + +```tsx +interface RenderSortIconProps { + sortDirection: SortDirection | undefined; +} +``` + +#### `RenderSortPriorityProps` + +Props for custom sort priority renderers. + +```tsx +interface RenderSortPriorityProps { + priority: number | undefined; +} +``` #### `DataGridHandle` -#### `RenderEditCellProps` +Handle type returned by `useImperativeHandle` for programmatic grid control. + +```tsx +interface DataGridHandle { + element: HTMLDivElement | null; + scrollToCell: (position: Partial) => void; + selectCell: (position: Position, options?: SelectCellOptions) => void; +} +``` + +**Example:** + +```tsx +import { useRef } from 'react'; +import { DataGrid, DataGridHandle } from 'react-data-grid'; + +function MyGrid() { + const gridRef = useRef(null); + + function scrollToTop() { + gridRef.current?.scrollToCell({ rowIdx: 0 }); + } + + return ; +} +``` + +#### `DefaultColumnOptions` + +Default options applied to all columns. + +```tsx +type DefaultColumnOptions = Pick< + Column, + 'minWidth' | 'maxWidth' | 'resizable' | 'sortable' | 'draggable' +>; +``` + +#### `Direction` + +Text direction for the grid. -#### `RenderRowProps` +```tsx +type Direction = 'ltr' | 'rtl'; +``` -#### `RenderCellProps` +#### `Maybe` -#### `RenderGroupCellProps` +Utility type for optional values. + +```tsx +type Maybe = T | undefined | null; +``` ### Generics From a010c108852e086eff3db4bc1cec4e2384ec1e9e Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 30 Oct 2025 17:19:36 +0000 Subject: [PATCH 02/17] immutable types / textEditor is a render function --- README.md | 58 ++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 440ef19267..64b1dd41c3 100644 --- a/README.md +++ b/README.md @@ -105,12 +105,12 @@ interface Row { title: string; } -const columns: Column[] = [ +const columns: readonly Column[] = [ { key: 'id', name: 'ID' }, { key: 'title', name: 'Title' } ]; -const rows: Row[] = [ +const rows: readonly Row[] = [ { id: 0, title: 'Example' }, { id: 1, title: 'Demo' } ]; @@ -591,28 +591,6 @@ test('grid', async () => { ###### `groupIdGetter?: Maybe<(groupKey: string, parentId?: string) => string>` -#### `textEditor` - -The default text editor component for editing cells. - -##### Props - -`RenderEditCellProps` - See the Types section below. - -**Example:** - -```tsx -import { textEditor } from 'react-data-grid'; - -const columns: Column[] = [ - { - key: 'title', - name: 'Title', - renderEditCell: textEditor - } -]; -``` - #### `` The default row component. Can be wrapped via the `renderers.renderRow` prop. @@ -738,7 +716,7 @@ The default header cell renderer. Renders sortable columns with sort indicators. ```tsx import { renderHeaderCell } from 'react-data-grid'; -const columns: Column[] = [ +const columns: readonly Column[] = [ { key: 'name', name: 'Name', @@ -748,6 +726,24 @@ const columns: Column[] = [ ]; ``` +#### `textEditor(props: RenderEditCellProps): ReactElement` + +The default text editor for editing cells. Returns a text input element. + +**Example:** + +```tsx +import { textEditor } from 'react-data-grid'; + +const columns: readonly Column[] = [ + { + key: 'title', + name: 'Title', + renderEditCell: textEditor + } +]; +``` + #### `renderSortIcon(props: RenderSortIconProps): ReactNode` Renders the sort direction arrow icon. @@ -801,7 +797,7 @@ Renders the expand/collapse toggle for grouped rows. ```tsx import { renderToggleGroup } from 'react-data-grid'; -const columns: Column[] = [ +const columns: readonly Column[] = [ { key: 'group', name: 'Group', @@ -819,7 +815,7 @@ A simple cell renderer that displays the cell value as text. ```tsx import { renderValue } from 'react-data-grid'; -const columns: Column[] = [ +const columns: readonly Column[] = [ { key: 'title', name: 'Title', @@ -857,7 +853,7 @@ A pre-configured column for row selection. Includes checkbox renderers for heade ```tsx import { DataGrid, SelectColumn } from 'react-data-grid'; -const columns = [SelectColumn, ...otherColumns]; +const columns: readonly Column[] = [SelectColumn, ...otherColumns]; function MyGrid() { return ( @@ -966,7 +962,7 @@ Function to determine how many columns this cell should span. Returns the number **Example:** ```tsx -const columns: Column[] = [ +const columns: readonly Column[] = [ { key: 'title', name: 'Title', @@ -1081,7 +1077,7 @@ interface ColumnGroup { **Example:** ```tsx -const columns = [ +const columns: readonly ColumnOrColumnGroup[] = [ { name: 'Personal Info', children: [ @@ -1425,7 +1421,7 @@ type ColSpanArgs = **Example:** ```tsx -const columns: Column[] = [ +const columns: readonly Column[] = [ { key: 'title', name: 'Title', From d36085c422d4240406119d6a6f804d63d6e50b39 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 30 Oct 2025 17:30:30 +0000 Subject: [PATCH 03/17] nit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64b1dd41c3..bf6cb1c498 100644 --- a/README.md +++ b/README.md @@ -611,7 +611,7 @@ The default cell component. Can be wrapped via the `renderers.renderCell` prop. #### `` -A formatter component for rendering selection checkboxes. +A formatter component for rendering row selection checkboxes. ##### Props From 4e02da0a49bca6e90d34aee78f0d7ce62b0f3387 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 30 Oct 2025 17:33:15 +0000 Subject: [PATCH 04/17] remove return types from titles --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index bf6cb1c498..c1d6b66f94 100644 --- a/README.md +++ b/README.md @@ -645,15 +645,15 @@ ID of the element that labels the checkbox. ### Hooks -#### `useHeaderRowSelection(): { isIndeterminate: boolean, isRowSelected: boolean, onRowSelectionChange: (event: SelectHeaderRowEvent) => void }` +#### `useHeaderRowSelection()` Hook for managing header row selection state. Used within custom header cell renderers to implement "select all" functionality. **Returns:** -- `isIndeterminate`: Whether some (but not all) rows are selected -- `isRowSelected`: Whether all rows are selected -- `onRowSelectionChange`: Callback to change selection state +- `isIndeterminate: boolean` - Whether some (but not all) rows are selected +- `isRowSelected: boolean` - Whether all rows are selected +- `onRowSelectionChange: (event: SelectHeaderRowEvent) => void` - Callback to change selection state **Example:** @@ -672,15 +672,15 @@ function CustomHeaderCell() { } ``` -#### `useRowSelection(): { isRowSelectionDisabled: boolean, isRowSelected: boolean, onRowSelectionChange: (event: SelectRowEvent) => void }` +#### `useRowSelection()` Hook for managing row selection state. Used within custom cell renderers to implement row selection. **Returns:** -- `isRowSelectionDisabled`: Whether selection is disabled for this row -- `isRowSelected`: Whether this row is selected -- `onRowSelectionChange`: Callback to change selection state +- `isRowSelectionDisabled: boolean` - Whether selection is disabled for this row +- `isRowSelected: boolean` - Whether this row is selected +- `onRowSelectionChange: (event: SelectRowEvent) => void` - Callback to change selection state **Example:** @@ -707,7 +707,7 @@ function CustomSelectCell({ row }: RenderCellProps) { ### Render Functions -#### `renderHeaderCell(props: RenderHeaderCellProps): ReactNode` +#### `renderHeaderCell(props: RenderHeaderCellProps)` The default header cell renderer. Renders sortable columns with sort indicators. @@ -726,7 +726,7 @@ const columns: readonly Column[] = [ ]; ``` -#### `textEditor(props: RenderEditCellProps): ReactElement` +#### `textEditor(props: RenderEditCellProps)` The default text editor for editing cells. Returns a text input element. @@ -744,7 +744,7 @@ const columns: readonly Column[] = [ ]; ``` -#### `renderSortIcon(props: RenderSortIconProps): ReactNode` +#### `renderSortIcon(props: RenderSortIconProps)` Renders the sort direction arrow icon. @@ -752,7 +752,7 @@ Renders the sort direction arrow icon. - `sortDirection: SortDirection | undefined` - 'ASC', 'DESC', or undefined -#### `renderSortPriority(props: RenderSortPriorityProps): ReactNode` +#### `renderSortPriority(props: RenderSortPriorityProps)` Renders the sort priority number for multi-column sorting. @@ -760,7 +760,7 @@ Renders the sort priority number for multi-column sorting. - `priority: number | undefined` - The sort priority (1, 2, 3, etc.) -#### `renderCheckbox(props: RenderCheckboxProps): ReactNode` +#### `renderCheckbox(props: RenderCheckboxProps)` Renders a checkbox input with proper styling and accessibility. @@ -784,7 +784,7 @@ const renderers = { }; ``` -#### `renderToggleGroup(props: RenderGroupCellProps): ReactNode` +#### `renderToggleGroup(props: RenderGroupCellProps)` Renders the expand/collapse toggle for grouped rows. @@ -806,7 +806,7 @@ const columns: readonly Column[] = [ ]; ``` -#### `renderValue(props: RenderCellProps): ReactNode` +#### `renderValue(props: RenderCellProps)` A simple cell renderer that displays the cell value as text. From 1cc5a0e18b983692eba2d6f4ace00b9a01890022 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 30 Oct 2025 17:38:59 +0000 Subject: [PATCH 05/17] fix incorrect generics --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c1d6b66f94..aad59cd16a 100644 --- a/README.md +++ b/README.md @@ -645,7 +645,7 @@ ID of the element that labels the checkbox. ### Hooks -#### `useHeaderRowSelection()` +#### `useHeaderRowSelection()` Hook for managing header row selection state. Used within custom header cell renderers to implement "select all" functionality. @@ -672,7 +672,7 @@ function CustomHeaderCell() { } ``` -#### `useRowSelection()` +#### `useRowSelection()` Hook for managing row selection state. Used within custom cell renderers to implement row selection. From 768b3be69b96afed4f4e3e20dc5672f9ff32d3c2 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 30 Oct 2025 17:42:44 +0000 Subject: [PATCH 06/17] nit --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index aad59cd16a..89bc6f0862 100644 --- a/README.md +++ b/README.md @@ -666,7 +666,7 @@ function CustomHeaderCell() { type="checkbox" checked={isRowSelected} indeterminate={isIndeterminate} - onChange={(e) => onRowSelectionChange({ checked: e.target.checked })} + onChange={(event) => onRowSelectionChange({ checked: event.target.checked })} /> ); } @@ -693,11 +693,11 @@ function CustomSelectCell({ row }: RenderCellProps) { type="checkbox" disabled={isRowSelectionDisabled} checked={isRowSelected} - onChange={(e) => + onChange={(event) => onRowSelectionChange({ row, - checked: e.target.checked, - isShiftClick: e.nativeEvent.shiftKey + checked: event.target.checked, + isShiftClick: event.nativeEvent.shiftKey }) } /> @@ -1176,7 +1176,7 @@ function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps onRowChange({ ...row, [column.key]: e.target.value })} + onChange={(event) => onRowChange({ ...row, [column.key]: event.target.value })} onBlur={() => onClose(true)} /> ); From 6aa50660969cafdcc20fed31dcb963bbb43c57d4 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 30 Oct 2025 18:01:27 +0000 Subject: [PATCH 07/17] tweaks --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 89bc6f0862..16fc217222 100644 --- a/README.md +++ b/README.md @@ -647,7 +647,7 @@ ID of the element that labels the checkbox. #### `useHeaderRowSelection()` -Hook for managing header row selection state. Used within custom header cell renderers to implement "select all" functionality. +Hook for managing header row selection state. Used within custom header cell renderers to implement custom "select all" functionality. **Returns:** @@ -674,7 +674,7 @@ function CustomHeaderCell() { #### `useRowSelection()` -Hook for managing row selection state. Used within custom cell renderers to implement row selection. +Hook for managing row selection state. Used within custom cell renderers to implement custom row selection. **Returns:** @@ -728,7 +728,7 @@ const columns: readonly Column[] = [ #### `textEditor(props: RenderEditCellProps)` -The default text editor for editing cells. Returns a text input element. +A basic text editor provided for convenience. **Example:** From 7cb5971643a43184a26051835e9e2db580f2a5b0 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 31 Oct 2025 17:24:18 +0000 Subject: [PATCH 08/17] tweak --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 16fc217222..1418f7d1e4 100644 --- a/README.md +++ b/README.md @@ -777,11 +777,13 @@ Renders a checkbox input with proper styling and accessibility. **Example:** ```tsx -import { renderCheckbox } from 'react-data-grid'; +import { DataGrid, renderCheckbox } from 'react-data-grid'; -const renderers = { - renderCheckbox: (props) => renderCheckbox({ ...props, 'aria-label': 'Select row' }) -}; + renderCheckbox({ ...props, 'aria-label': 'Select row' }) + }} +/>; ``` #### `renderToggleGroup(props: RenderGroupCellProps)` From 66cb2533dab21fbad60d1bc679fba28068a3af52 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 31 Oct 2025 17:29:05 +0000 Subject: [PATCH 09/17] add missing imports --- README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1418f7d1e4..bc21df4701 100644 --- a/README.md +++ b/README.md @@ -714,7 +714,7 @@ The default header cell renderer. Renders sortable columns with sort indicators. **Example:** ```tsx -import { renderHeaderCell } from 'react-data-grid'; +import { renderHeaderCell, type Column } from 'react-data-grid'; const columns: readonly Column[] = [ { @@ -733,7 +733,7 @@ A basic text editor provided for convenience. **Example:** ```tsx -import { textEditor } from 'react-data-grid'; +import { textEditor, type Column } from 'react-data-grid'; const columns: readonly Column[] = [ { @@ -797,7 +797,7 @@ Renders the expand/collapse toggle for grouped rows. **Example:** ```tsx -import { renderToggleGroup } from 'react-data-grid'; +import { renderToggleGroup, type Column } from 'react-data-grid'; const columns: readonly Column[] = [ { @@ -815,7 +815,7 @@ A simple cell renderer that displays the cell value as text. **Example:** ```tsx -import { renderValue } from 'react-data-grid'; +import { renderValue, type Column } from 'react-data-grid'; const columns: readonly Column[] = [ { @@ -853,7 +853,7 @@ A pre-configured column for row selection. Includes checkbox renderers for heade **Example:** ```tsx -import { DataGrid, SelectColumn } from 'react-data-grid'; +import { DataGrid, SelectColumn, type Column } from 'react-data-grid'; const columns: readonly Column[] = [SelectColumn, ...otherColumns]; @@ -964,6 +964,8 @@ Function to determine how many columns this cell should span. Returns the number **Example:** ```tsx +import type { Column } from 'react-data-grid'; + const columns: readonly Column[] = [ { key: 'title', @@ -1079,6 +1081,8 @@ interface ColumnGroup { **Example:** ```tsx +import type { ColumnOrColumnGroup } from 'react-data-grid'; + const columns: readonly ColumnOrColumnGroup[] = [ { name: 'Personal Info', @@ -1133,6 +1137,8 @@ interface RenderCellProps { **Example:** ```tsx +import type { RenderCellProps } from 'react-data-grid'; + function CustomCell({ row, column, onRowChange }: RenderCellProps) { return (
@@ -1173,6 +1179,8 @@ interface RenderEditCellProps { **Example:** ```tsx +import type { RenderEditCellProps } from 'react-data-grid'; + function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps) { return ( , event: CellMouseEvent) { console.log('Clicked cell at row', args.rowIdx, 'column', args.column.key); args.selectCell(true); // Select and start editing @@ -1308,6 +1318,8 @@ Returns whether `preventGridDefault` was called. **Example:** ```tsx +import type { CellMouseArgs, CellMouseEvent } from 'react-data-grid'; + function onCellClick(args: CellMouseArgs, event: CellMouseEvent) { if (args.column.key === 'actions') { event.preventGridDefault(); // Prevent cell selection @@ -1367,6 +1379,8 @@ interface EditCellKeyDownArgs { **Example:** ```tsx +import type { CellKeyDownArgs, CellKeyboardEvent } from 'react-data-grid'; + function onCellKeyDown(args: CellKeyDownArgs, event: CellKeyboardEvent) { if (args.mode === 'EDIT' && event.key === 'Escape') { args.onClose(false); // Close without committing @@ -1423,6 +1437,8 @@ type ColSpanArgs = **Example:** ```tsx +import type { Column } from 'react-data-grid'; + const columns: readonly Column[] = [ { key: 'title', From 1d982190f4220663945266896d84911a6c0dcd51 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 31 Oct 2025 17:36:01 +0000 Subject: [PATCH 10/17] tweak --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bc21df4701..73ff275461 100644 --- a/README.md +++ b/README.md @@ -810,7 +810,7 @@ const columns: readonly Column[] = [ #### `renderValue(props: RenderCellProps)` -A simple cell renderer that displays the cell value as text. +The default cell renderer that renders the value of `row[column.key]`. **Example:** @@ -830,17 +830,25 @@ const columns: readonly Column[] = [ #### `DataGridDefaultRenderersContext` -Context for providing default renderers to the DataGrid. Used internally but can be useful for deeply nested custom components that need access to default renderers. +Context for providing default renderers to DataGrids in your app. **Example:** ```tsx -import { DataGridDefaultRenderersContext } from 'react-data-grid'; -import { useContext } from 'react'; +import { DataGridDefaultRenderersContext, type Renderers } from 'react-data-grid'; -function CustomComponent() { - const renderers = useContext(DataGridDefaultRenderersContext); - return renderers?.renderCheckbox?.({ ... }); +// custom implementations of renderers +const defaultGridRenderers: Renderers = { + renderCheckbox, + renderSortStatus +}; + +function AppProvider({ children }) { + return ( + + {children} + + ); } ``` @@ -1379,7 +1387,7 @@ interface EditCellKeyDownArgs { **Example:** ```tsx -import type { CellKeyDownArgs, CellKeyboardEvent } from 'react-data-grid'; +import type { CellKeyboardEvent, CellKeyDownArgs } from 'react-data-grid'; function onCellKeyDown(args: CellKeyDownArgs, event: CellKeyboardEvent) { if (args.mode === 'EDIT' && event.key === 'Escape') { From 2993a1bee1df1b84993a08c14821765e70bc3198 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 31 Oct 2025 17:57:08 +0000 Subject: [PATCH 11/17] more tweaks --- README.md | 33 +++++++++++++++++++-------------- src/types.ts | 4 ++-- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 73ff275461..b5ec2d8a84 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,14 @@ const columns: readonly Column[] = [ // other columns ]; +function rowKeyGetter(row: Row) { + return row.id; +} + +function isRowSelectionDisabled(row: Row) { + return !row.isActive; +} + function MyGrid() { const [selectedRows, setSelectedRows] = useState((): ReadonlySet => new Set()); @@ -266,14 +274,6 @@ function MyGrid() { /> ); } - -function rowKeyGetter(row: Row) { - return row.id; -} - -function isRowSelectionDisabled(row: Row) { - return !row.isActive; -} ``` ###### `sortColumns?: Maybe` @@ -856,7 +856,8 @@ function AppProvider({ children }) { #### `SelectColumn: Column` -A pre-configured column for row selection. Includes checkbox renderers for header, regular rows, and grouped rows. +A pre-configured column for row selection. +Includes checkbox renderers for header, regular rows, and grouped rows. **Example:** @@ -865,12 +866,16 @@ import { DataGrid, SelectColumn, type Column } from 'react-data-grid'; const columns: readonly Column[] = [SelectColumn, ...otherColumns]; +function rowKeyGetter(row: Row) { + return row.id; +} + function MyGrid() { return ( row.id} + rowKeyGetter={rowKeyGetter} selectedRows={selectedRows} onSelectedRowsChange={setSelectedRows} /> @@ -887,7 +892,7 @@ The key used for the `SelectColumn`. Useful for identifying or filtering the sel ```tsx import { SELECT_COLUMN_KEY } from 'react-data-grid'; -const nonSelectColumns = columns.filter((col) => col.key !== SELECT_COLUMN_KEY); +const nonSelectColumns = columns.filter((column) => column.key !== SELECT_COLUMN_KEY); ``` ### Types @@ -931,7 +936,7 @@ Maximum column width in pixels. ##### `cellClass?: Maybe Maybe)>` -Class name(s) for the cell. Can be a string or a function that returns a class name based on the row. +Class name(s) for cells. Can be a string or a function that returns a class name based on the row. ##### `headerCellClass?: Maybe` @@ -939,7 +944,7 @@ Class name(s) for the header cell. ##### `summaryCellClass?: Maybe Maybe)>` -Class name(s) for the summary cell. Can be a string or a function that returns a class name based on the summary row. +Class name(s) for summary cells. Can be a string or a function that returns a class name based on the summary row. ##### `renderCell?: Maybe<(props: RenderCellProps) => ReactNode>` @@ -963,7 +968,7 @@ Render function to render the content of edit cells. When set, the column is aut ##### `editable?: Maybe boolean)>` -Enables cell editing. If set and no editor property specified, then a text input will be used as the cell editor. +Control whether cells can be edited with `renderEditCell`. ##### `colSpan?: Maybe<(args: ColSpanArgs) => Maybe>` diff --git a/src/types.ts b/src/types.ts index 96d0013147..d431067248 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,11 +25,11 @@ export interface Column { readonly minWidth?: Maybe; /** Maximum column width in pixels */ readonly maxWidth?: Maybe; - /** Class name(s) for the cell */ + /** Class name(s) for cells */ readonly cellClass?: Maybe Maybe)>; /** Class name(s) for the header cell */ readonly headerCellClass?: Maybe; - /** Class name(s) for the summary cell */ + /** Class name(s) for summary cells */ readonly summaryCellClass?: Maybe Maybe)>; /** Render function to render the content of cells */ readonly renderCell?: Maybe<(props: RenderCellProps) => ReactNode>; From 7fb07a9dd5b52885e371d7a1bf6d554384c364ea Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Mon, 3 Nov 2025 17:04:39 +0000 Subject: [PATCH 12/17] tweaks --- README.md | 70 ++++++++++++++++++++++++++-------------------------- src/types.ts | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index b5ec2d8a84..6b1cc4ce91 100644 --- a/README.md +++ b/README.md @@ -1031,7 +1031,7 @@ Options for cell editing. **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. +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. ###### `commitOnOutsideClick?: Maybe` @@ -1043,7 +1043,39 @@ Commit changes when clicking outside the cell. **Default**: `true` -Close the editor when the row changes externally. +Close the editor when the row value changes externally. + +#### `ColumnGroup` + +Defines a group of columns that share a common header. + +```tsx +interface ColumnGroup { + readonly name: string | ReactElement; + readonly headerCellClass?: Maybe; + readonly children: readonly ColumnOrColumnGroup[]; +} +``` + +**Example:** + +```tsx +import type { ColumnOrColumnGroup } from 'react-data-grid'; + +const columns: readonly ColumnOrColumnGroup[] = [ + { + name: 'Personal Info', + children: [ + { key: 'firstName', name: 'First Name' }, + { key: 'lastName', name: 'Last Name' } + ] + } +]; +``` + +#### `ColumnOrColumnGroup` + +Union type representing either a `Column` or a `ColumnGroup`. #### `CalculatedColumn` @@ -1054,7 +1086,7 @@ Extends `Column` with additional computed properties used internally by the grid - `idx: number` - The column index - `level: number` - Nesting level when using column groups - `parent: CalculatedColumnParent | undefined` - Parent column group if nested -- All optional Column properties become required with default values +- Multiple Column properties have their values set to their default value #### `CalculatedColumnParent` @@ -1079,38 +1111,6 @@ Union type representing either a `CalculatedColumnParent` or a `CalculatedColumn type CalculatedColumnOrColumnGroup = CalculatedColumnParent | CalculatedColumn; ``` -#### `ColumnGroup` - -Defines a group of columns that share a common header. - -```tsx -interface ColumnGroup { - readonly name: string | ReactElement; - readonly headerCellClass?: Maybe; - readonly children: readonly ColumnOrColumnGroup[]; -} -``` - -**Example:** - -```tsx -import type { ColumnOrColumnGroup } from 'react-data-grid'; - -const columns: readonly ColumnOrColumnGroup[] = [ - { - name: 'Personal Info', - children: [ - { key: 'firstName', name: 'First Name' }, - { key: 'lastName', name: 'Last Name' } - ] - } -]; -``` - -#### `ColumnOrColumnGroup` - -Union type representing either a `Column` or a `ColumnGroup`. - #### `RowHeightArgs` Arguments passed to the `rowHeight` function when it's a function. diff --git a/src/types.ts b/src/types.ts index d431067248..3222b60e26 100644 --- a/src/types.ts +++ b/src/types.ts @@ -59,7 +59,7 @@ export interface Column { /** Options for cell editing */ readonly editorOptions?: Maybe<{ /** - * Render the cell content in addition to the edit cell. + * 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. * By default, the cell content is not rendered when the edit cell is open. * @default false @@ -71,7 +71,7 @@ export interface Column { */ readonly commitOnOutsideClick?: Maybe; /** - * Close the editor when the row changes externally + * Close the editor when the row value changes externally * @default true */ readonly closeOnExternalRowChange?: Maybe; From 51189a12bb5d5a5f01c546856ae0ac2586475291 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Mon, 3 Nov 2025 18:03:09 +0000 Subject: [PATCH 13/17] tweaks --- README.md | 6 +++--- src/DataGrid.tsx | 33 +++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 6b1cc4ce91..ca0d69a8a0 100644 --- a/README.md +++ b/README.md @@ -1152,7 +1152,7 @@ interface RenderCellProps { ```tsx import type { RenderCellProps } from 'react-data-grid'; -function CustomCell({ row, column, onRowChange }: RenderCellProps) { +function renderCell({ row, column, onRowChange }: RenderCellProps) { return (
{row[column.key]} @@ -1637,7 +1637,7 @@ interface RenderSortPriorityProps { #### `DataGridHandle` -Handle type returned by `useImperativeHandle` for programmatic grid control. +Handle type assigned to a grid's `ref` for programmatic grid control. ```tsx interface DataGridHandle { @@ -1677,7 +1677,7 @@ type DefaultColumnOptions = Pick< #### `Direction` -Text direction for the grid. +Grid layout bidirectionality. ```tsx type Direction = 'ltr' | 'rtl'; diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 27d34b0ab7..b8532c13fd 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -531,20 +531,25 @@ export function DataGrid(props: DataGridPr } }, [shouldFocusCell, focusCell, selectedPosition.idx]); - useImperativeHandle(ref, () => ({ - element: gridRef.current, - scrollToCell({ idx, rowIdx }) { - const scrollToIdx = - idx !== undefined && idx > lastFrozenColumnIndex && idx < columns.length ? idx : undefined; - const scrollToRowIdx = - rowIdx !== undefined && isRowIdxWithinViewportBounds(rowIdx) ? rowIdx : undefined; - - if (scrollToIdx !== undefined || scrollToRowIdx !== undefined) { - setScrollToPosition({ idx: scrollToIdx, rowIdx: scrollToRowIdx }); - } - }, - selectCell - })); + useImperativeHandle( + ref, + (): DataGridHandle => ({ + element: gridRef.current, + scrollToCell({ idx, rowIdx }) { + const scrollToIdx = + idx !== undefined && idx > lastFrozenColumnIndex && idx < columns.length + ? idx + : undefined; + const scrollToRowIdx = + rowIdx !== undefined && isRowIdxWithinViewportBounds(rowIdx) ? rowIdx : undefined; + + if (scrollToIdx !== undefined || scrollToRowIdx !== undefined) { + setScrollToPosition({ idx: scrollToIdx, rowIdx: scrollToRowIdx }); + } + }, + selectCell + }) + ); /** * event handlers From 6c3cc8a8a2f75fd9cad5a1d487d33d00f36313b7 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Mon, 3 Nov 2025 18:31:01 +0000 Subject: [PATCH 14/17] add some performance notes --- README.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca0d69a8a0..2266d860d1 100644 --- a/README.md +++ b/README.md @@ -136,12 +136,27 @@ Set `--rdg-color-scheme: light/dark` at the `:root` to control the color theme. An array of column definitions. Each column should have a key and name. See the [`Column`](#columntrow-tsummaryrow) type for all available options. -: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. +:warning: **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. ###### `rows: readonly R[]` An array of rows, the rows data can be of any type. +:bulb: **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: + + ```tsx + // ✅ 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, causing all visible rows to re-render + setRows(rows.map((row) => ({ ...row }))); + ``` + ###### `topSummaryRows?: Maybe` Rows pinned at the top of the grid for summary purposes. @@ -173,6 +188,8 @@ function MyGrid() { :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. +:warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to prevent unnecessary re-renders. + ###### `onRowsChange?: Maybe<(rows: R[], data: RowsChangeData) => void>` Callback triggered when rows are changed. @@ -197,6 +214,8 @@ function MyGrid() { Height of each row in pixels. A function can be used to set different row heights. +:warning: **Performance:** When using a function, the height of all rows is calculated upfront on every render. For large datasets (1000+ rows), this can cause performance issues. Consider using a fixed height when possible, or memoize the `rowHeight` function. + ###### `headerRowHeight?: Maybe` **Default:** `35` pixels @@ -507,8 +526,6 @@ function MyGrid() { } ``` -:warning: To prevent all rows from being unmounted on re-renders, make sure to pass a static or memoized render function to `renderRow`. - ###### `rowClass?: Maybe<(row: R, rowIdx: number) => Maybe>` Function to apply custom class names to rows. @@ -525,6 +542,8 @@ function rowClass(row: Row, rowIdx: number) { } ``` +:warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to avoid re-rendering all rows on every render. + ###### `headerRowClass?: Maybe>` Custom class name for the header row. From b933f8686c2337d3d36b1e8f2f1070cdf8f51361 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 5 Nov 2025 17:19:22 +0000 Subject: [PATCH 15/17] remove ref line --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 2266d860d1..ac8616e49f 100644 --- a/README.md +++ b/README.md @@ -618,8 +618,6 @@ The default row component. Can be wrapped via the `renderers.renderRow` prop. `RenderRowProps` - See the Types section below. -The `ref` prop is supported. - #### `` The default cell component. Can be wrapped via the `renderers.renderCell` prop. From 152dfd0f0580b09233b2e2cc1df62af7ac4ed25d Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 5 Nov 2025 17:19:53 +0000 Subject: [PATCH 16/17] add links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ac8616e49f..4ff4546cec 100644 --- a/README.md +++ b/README.md @@ -616,7 +616,7 @@ The default row component. Can be wrapped via the `renderers.renderRow` prop. ##### Props -`RenderRowProps` - See the Types section below. +[`RenderRowProps`](#renderrowpropstrow-tsummaryrow) #### `` @@ -624,7 +624,7 @@ The default cell component. Can be wrapped via the `renderers.renderCell` prop. ##### Props -`CellRendererProps` - See the Types section below. +[`CellRendererProps`](#cellrendererpropstrow-tsummaryrow) #### `` @@ -809,7 +809,7 @@ Renders the expand/collapse toggle for grouped rows. ##### Props -`RenderGroupCellProps` - See the Types section below. +[`RenderGroupCellProps`](#rendergroupcellpropstrow-tsummaryrow) **Example:** From 75911c38287e8b2370ff462916b9082e951e1b93 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien <567105+nstepien@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:21:43 +0000 Subject: [PATCH 17/17] Update README.md Co-authored-by: Aman Mahajan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ff4546cec..b84a22598f 100644 --- a/README.md +++ b/README.md @@ -805,7 +805,7 @@ import { DataGrid, renderCheckbox } from 'react-data-grid'; #### `renderToggleGroup(props: RenderGroupCellProps)` -Renders the expand/collapse toggle for grouped rows. +The default group cell renderer used by the columns used for grouping (`groupBy` prop). This renders the expand/collapse toggle. ##### Props