Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e1e83d1
Multiple renames for clarity and consistency
nstepien Feb 21, 2026
83674a9
Merge remote-tracking branch 'origin/main' into clarity
nstepien Feb 23, 2026
4ba6b57
fix SelectCellKeyDownArgs type in README
nstepien Feb 23, 2026
944babe
lint
nstepien Feb 23, 2026
07e3af6
tweak SortableHeaderCell
nstepien Feb 23, 2026
548fc22
tweak EditCell
nstepien Feb 23, 2026
6cffef1
fix selectedCellEditor type
nstepien Feb 23, 2026
794687c
GroupRowRendererProps -> GroupedRowProps
nstepien Feb 23, 2026
4b4318b
Merge branch 'main' into clarity
nstepien Feb 24, 2026
453e458
Merge branch 'main' into clarity
nstepien Feb 24, 2026
d5f94fa
Merge branch 'main' into clarity
nstepien Feb 26, 2026
1f09988
Merge branch 'main' into clarity
nstepien Mar 2, 2026
cb4eff9
Merge branch 'main' into clarity
nstepien Mar 5, 2026
007fd79
Merge branch 'main' into clarity
nstepien Mar 6, 2026
9306b3f
Merge branch 'main' into clarity
nstepien Mar 10, 2026
b2da515
Merge branch 'main' into clarity
nstepien Mar 11, 2026
d9ac713
Merge branch 'main' into clarity
nstepien Mar 18, 2026
fd88bc8
Merge branch 'main' into clarity
nstepien Mar 27, 2026
6d4c58a
Merge branch 'main' into clarity
nstepien Apr 7, 2026
bd3196b
Merge branch 'main' into clarity
nstepien Apr 8, 2026
19dc6f9
Merge branch 'main' into clarity
nstepien Apr 25, 2026
6fefa25
fix typos
nstepien Apr 29, 2026
acd6f65
Merge branch 'main' into clarity
nstepien Jun 23, 2026
dd4d7e6
Merge branch 'main' into clarity
nstepien Jun 24, 2026
58f38fc
Merge branch 'main' into clarity
nstepien Jul 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 36 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ Control column widths using the [`width`](#width-maybenumber--string), [`minWidt

### Custom Renderers

Replace default components with custom implementations using the [`renderers`](#renderers-mayberenderersr-sr) prop. Columns can also have custom renderers using the [`renderCell`](#rendercell-maybeprops-rendercellpropstrow-tsummaryrow--reactnode), [`renderHeaderCell`](#renderheadercell-maybeprops-renderheadercellpropstrow-tsummaryrow--reactnode), [`renderSummaryCell`](#rendersummarycell-maybeprops-rendersummarycellpropstsummaryrow-trow--reactnode), [`renderGroupCell`](#rendergroupcell-maybeprops-rendergroupcellpropstrow-tsummaryrow--reactnode), and [`renderEditCell`](#rendereditcell-maybeprops-rendereditcellpropstrow-tsummaryrow--reactnode) properties.
Replace default components with custom implementations using the [`renderers`](#renderers-mayberenderersr-sr) prop. Columns can also have custom renderers using the [`renderCell`](#rendercell-maybeprops-rendercellcontentpropstrow-tsummaryrow--reactnode), [`renderHeaderCell`](#renderheadercell-maybeprops-renderheadercellcontentpropstrow-tsummaryrow--reactnode), [`renderSummaryCell`](#rendersummarycell-maybeprops-rendersummarycellcontentpropstsummaryrow-trow--reactnode), [`renderGroupCell`](#rendergroupcell-maybeprops-rendergroupcellcontentpropstrow-tsummaryrow--reactnode), and [`renderEditCell`](#rendereditcell-maybeprops-rendereditcellcontentpropstrow-tsummaryrow--reactnode) properties.

## API Reference

Expand Down Expand Up @@ -852,6 +852,8 @@ function rowGrouper(rows: readonly Row[], columnKey: string): Record<string, rea
}
```

:warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to prevent unnecessary re-renders.

###### `expandedGroupIds: ReadonlySet<unknown>`

**Required.** A set of group IDs that are currently expanded. Group IDs are generated by `groupIdGetter`.
Expand Down Expand Up @@ -881,6 +883,8 @@ function MyGrid() {

Function to generate unique IDs for group rows. If not provided, a default implementation is used that concatenates parent and group keys with `__`.

:warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to prevent unnecessary re-renders.

###### `rowHeight?: Maybe<number | ((args: RowHeightArgs<R>) => number)>`

**Note:** Unlike `DataGrid`, the `rowHeight` function receives [`RowHeightArgs<R>`](#rowheightargstrow) which includes a `type` property to distinguish between regular rows and group rows:
Expand Down Expand Up @@ -910,11 +914,11 @@ The default cell component. Can be wrapped via the `renderers.renderCell` prop.

##### Props

[`CellRendererProps<TRow, TSummaryRow>`](#cellrendererpropstrow-tsummaryrow)
[`RenderCellProps<TRow, TSummaryRow>`](#rendercellpropstrow-tsummaryrow)

#### `<SelectCellFormatter />`
#### `<SelectCheckbox />`

A formatter component for rendering row selection checkboxes.
A component for rendering row selection checkboxes.

##### Props

Expand Down Expand Up @@ -1001,7 +1005,7 @@ Hook for managing row selection state. Used within custom cell renderers to impl
**Example:**

```tsx
function CustomSelectCell({ row }: RenderCellProps<Row>) {
function CustomSelectCell({ row }: RenderCellContentProps<Row>) {
const { isRowSelectionDisabled, isRowSelected, onRowSelectionChange } = useRowSelection();

return (
Expand All @@ -1023,7 +1027,7 @@ function CustomSelectCell({ row }: RenderCellProps<Row>) {

### Render Functions

#### `renderHeaderCell<R, SR>(props: RenderHeaderCellProps<R, SR>)`
#### `renderHeaderCell<R, SR>(props: RenderHeaderCellContentProps<R, SR>)`

The default header cell renderer. Renders sortable columns with sort indicators.

Expand All @@ -1042,7 +1046,7 @@ const columns: readonly Column<Row>[] = [
];
```

#### `renderTextEditor<TRow, TSummaryRow>(props: RenderEditCellProps<TRow, TSummaryRow>)`
#### `renderTextEditor<TRow, TSummaryRow>(props: RenderEditCellContentProps<TRow, TSummaryRow>)`

A basic text editor provided for convenience.

Expand Down Expand Up @@ -1102,13 +1106,13 @@ import { DataGrid, renderCheckbox } from 'react-data-grid';
/>;
```

#### `renderToggleGroup<R, SR>(props: RenderGroupCellProps<R, SR>)`
#### `renderToggleGroup<R, SR>(props: RenderGroupCellContentProps<R, SR>)`

The default group cell renderer used by the columns used for grouping (`groupBy` prop). This renders the expand/collapse toggle.

##### Props

[`RenderGroupCellProps<TRow, TSummaryRow>`](#rendergroupcellpropstrow-tsummaryrow)
[`RenderGroupCellContentProps<TRow, TSummaryRow>`](#rendergroupcellcontentpropstrow-tsummaryrow)

**Example:**

Expand All @@ -1124,7 +1128,7 @@ const columns: readonly Column<Row>[] = [
];
```

#### `renderValue<R, SR>(props: RenderCellProps<R, SR>)`
#### `renderValue<R, SR>(props: RenderCellContentProps<R, SR>)`

The default cell renderer that renders the value of `row[column.key]`.

Expand Down Expand Up @@ -1330,23 +1334,23 @@ Class name(s) for the header cell.

Class name(s) for summary cells. Can be a string or a function that returns a class name based on the summary row.

##### `renderCell?: Maybe<(props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderCell?: Maybe<(props: RenderCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of cells.

##### `renderHeaderCell?: Maybe<(props: RenderHeaderCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderHeaderCell?: Maybe<(props: RenderHeaderCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of the header cell.

##### `renderSummaryCell?: Maybe<(props: RenderSummaryCellProps<TSummaryRow, TRow>) => ReactNode>`
##### `renderSummaryCell?: Maybe<(props: RenderSummaryCellContentProps<TSummaryRow, TRow>) => ReactNode>`

Render function to render the content of summary cells

##### `renderGroupCell?: Maybe<(props: RenderGroupCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderGroupCell?: Maybe<(props: RenderGroupCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of group cells when using `TreeDataGrid`.

##### `renderEditCell?: Maybe<(props: RenderEditCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderEditCell?: Maybe<(props: RenderEditCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of edit cells. When set, the column is automatically set to be editable

Expand Down Expand Up @@ -1528,12 +1532,12 @@ function getRowHeight(args: RowHeightArgs<Row>): number {
<TreeDataGrid rowHeight={getRowHeight} ... />
```

#### `RenderCellProps<TRow, TSummaryRow>`
#### `RenderCellContentProps<TRow, TSummaryRow>`

Props passed to custom cell renderers.

```tsx
interface RenderCellProps<TRow, TSummaryRow = unknown> {
interface RenderCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
Expand All @@ -1546,9 +1550,9 @@ interface RenderCellProps<TRow, TSummaryRow = unknown> {
**Example:**

```tsx
import type { RenderCellProps } from 'react-data-grid';
import type { RenderCellContentProps } from 'react-data-grid';

function renderCell({ row, column, onRowChange }: RenderCellProps<MyRow>) {
function renderCell({ row, column, onRowChange }: RenderCellContentProps<MyRow>) {
return (
<div>
{row[column.key]}
Expand All @@ -1558,25 +1562,25 @@ function renderCell({ row, column, onRowChange }: RenderCellProps<MyRow>) {
}
```

#### `RenderHeaderCellProps<TRow, TSummaryRow>`
#### `RenderHeaderCellContentProps<TRow, TSummaryRow>`

Props passed to custom header cell renderers.

```tsx
interface RenderHeaderCellProps<TRow, TSummaryRow = unknown> {
interface RenderHeaderCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
sortDirection: SortDirection | undefined;
priority: number | undefined;
tabIndex: number;
}
```

#### `RenderEditCellProps<TRow, TSummaryRow>`
#### `RenderEditCellContentProps<TRow, TSummaryRow>`

Props passed to custom edit cell renderers (editors).

```tsx
interface RenderEditCellProps<TRow, TSummaryRow = unknown> {
interface RenderEditCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
Expand All @@ -1588,9 +1592,9 @@ interface RenderEditCellProps<TRow, TSummaryRow = unknown> {
**Example:**

```tsx
import type { RenderEditCellProps } from 'react-data-grid';
import type { RenderEditCellContentProps } from 'react-data-grid';

function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps<MyRow>) {
function renderEditor({ row, column, onRowChange, onClose }: RenderEditCellContentProps<MyRow>) {
return (
<input
autoFocus
Expand All @@ -1602,24 +1606,24 @@ function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps
}
```

#### `RenderSummaryCellProps<TSummaryRow, TRow>`
#### `RenderSummaryCellContentProps<TSummaryRow, TRow>`

Props passed to summary cell renderers.

```tsx
interface RenderSummaryCellProps<TSummaryRow, TRow = unknown> {
interface RenderSummaryCellContentProps<TSummaryRow, TRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TSummaryRow;
tabIndex: number;
}
```

#### `RenderGroupCellProps<TRow, TSummaryRow>`
#### `RenderGroupCellContentProps<TRow, TSummaryRow>`

Props passed to group cell renderers when using `TreeDataGrid`.

```tsx
interface RenderGroupCellProps<TRow, TSummaryRow = unknown> {
interface RenderGroupCellContentProps<TRow, TSummaryRow = unknown> {
groupKey: unknown;
column: CalculatedColumn<TRow, TSummaryRow>;
row: GroupRow<TRow>;
Expand All @@ -1644,15 +1648,15 @@ interface RenderRowProps<TRow, TSummaryRow = unknown> {
isRowSelected: boolean;
gridRowStart: number;
draggedOverCellIdx: number | undefined;
activeCellEditor: ReactElement<RenderEditCellProps<TRow>> | undefined;
activeCellEditor: ReactElement<EditCellProps<TRow, TSummaryRow>> | undefined;
onRowChange: (column: CalculatedColumn<TRow, TSummaryRow>, rowIdx: number, newRow: TRow) => void;
rowClass: Maybe<(row: TRow, rowIdx: number) => Maybe<string>>;
isTreeGrid: boolean;
// ... and event handlers
}
```

#### `CellRendererProps<TRow, TSummaryRow>`
#### `RenderCellProps<TRow, TSummaryRow>`

Props passed to the cell renderer when using `renderers.renderCell`.

Expand All @@ -1664,7 +1668,7 @@ Custom renderer configuration for the grid.

```tsx
interface Renderers<TRow, TSummaryRow> {
renderCell?: Maybe<(key: Key, props: CellRendererProps<TRow, TSummaryRow>) => ReactNode>;
renderCell?: Maybe<(key: Key, props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>;
renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>;
renderRow?: Maybe<(key: Key, props: RenderRowProps<TRow, TSummaryRow>) => ReactNode>;
renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>;
Expand Down
12 changes: 6 additions & 6 deletions src/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { css } from 'ecij';

import { useRovingTabIndex } from './hooks';
import { createCellEvent, getCellClassname, getCellStyle, isCellEditableUtil } from './utils';
import type { CellMouseEventHandler, CellRendererProps } from './types';
import type { CellMouseEventHandler, RenderCellProps } from './types';

const cellDraggedOver = css`
@layer rdg.Cell {
Expand Down Expand Up @@ -33,7 +33,7 @@ function Cell<R, SR>({
setActivePosition,
style,
...props
}: CellRendererProps<R, SR>) {
}: RenderCellProps<R, SR>) {
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellActive);

const { cellClass } = column;
Expand Down Expand Up @@ -124,10 +124,10 @@ function Cell<R, SR>({
);
}

const CellComponent = memo(Cell) as <R, SR>(props: CellRendererProps<R, SR>) => React.JSX.Element;
const MemoCell = memo(Cell) as <R, SR>(props: RenderCellProps<R, SR>) => React.JSX.Element;

export default CellComponent;
export { MemoCell as Cell };

export function defaultRenderCell<R, SR>(key: React.Key, props: CellRendererProps<R, SR>) {
return <CellComponent key={key} {...props} />;
export function defaultRenderCell<R, SR>(key: React.Key, props: RenderCellProps<R, SR>) {
return <MemoCell key={key} {...props} />;
}
27 changes: 16 additions & 11 deletions src/Columns.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { useHeaderRowSelection, useRowSelection } from './hooks';
import type { Column, RenderCellProps, RenderGroupCellProps, RenderHeaderCellProps } from './types';
import { SelectCellFormatter } from './cellRenderers';
import type {
Column,
RenderCellContentProps,
RenderGroupCellContentProps,
RenderHeaderCellContentProps
} from './types';
import { SelectCheckbox } from './cellRenderers';

export const SELECT_COLUMN_KEY = 'rdg-select-column';

function HeaderRenderer({ tabIndex }: RenderHeaderCellProps<unknown>) {
function SelectAllCell({ tabIndex }: RenderHeaderCellContentProps<unknown>) {
const { isIndeterminate, isRowSelected, onRowSelectionChange } = useHeaderRowSelection();

return (
<SelectCellFormatter
<SelectCheckbox
aria-label="Select All"
tabIndex={tabIndex}
indeterminate={isIndeterminate}
Expand All @@ -20,11 +25,11 @@ function HeaderRenderer({ tabIndex }: RenderHeaderCellProps<unknown>) {
);
}

function SelectFormatter({ row, tabIndex }: RenderCellProps<unknown>) {
function RowSelectCell({ row, tabIndex }: RenderCellContentProps<unknown>) {
const { isRowSelectionDisabled, isRowSelected, onRowSelectionChange } = useRowSelection();

return (
<SelectCellFormatter
<SelectCheckbox
aria-label="Select"
tabIndex={tabIndex}
disabled={isRowSelectionDisabled}
Expand All @@ -36,11 +41,11 @@ function SelectFormatter({ row, tabIndex }: RenderCellProps<unknown>) {
);
}

function SelectGroupFormatter({ row, tabIndex }: RenderGroupCellProps<unknown>) {
function GroupSelectCell({ row, tabIndex }: RenderGroupCellContentProps<unknown>) {
const { isRowSelected, onRowSelectionChange } = useRowSelection();

return (
<SelectCellFormatter
<SelectCheckbox
aria-label="Select Group"
tabIndex={tabIndex}
value={isRowSelected}
Expand All @@ -62,12 +67,12 @@ export const SelectColumn: Column<any, any> = {
sortable: false,
frozen: true,
renderHeaderCell(props) {
return <HeaderRenderer {...props} />;
return <SelectAllCell {...props} />;
},
renderCell(props) {
return <SelectFormatter {...props} />;
return <RowSelectCell {...props} />;
},
renderGroupCell(props) {
return <SelectGroupFormatter {...props} />;
return <GroupSelectCell {...props} />;
}
};
11 changes: 6 additions & 5 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -498,15 +498,15 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
*/
const handleColumnResizeLatest = useLatestFunc(handleColumnResize);
const handleColumnResizeEndLatest = useLatestFunc(handleColumnResizeEnd);
const onColumnsReorderLastest = useLatestFunc(onColumnsReorder);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Lastest" 🙈

const onColumnsReorderLatest = useLatestFunc(onColumnsReorder);
const onSortColumnsChangeLatest = useLatestFunc(onSortColumnsChange);
const onCellMouseDownLatest = useLatestFunc(onCellMouseDown);
const onCellClickLatest = useLatestFunc(onCellClick);
const onCellDoubleClickLatest = useLatestFunc(onCellDoubleClick);
const onCellContextMenuLatest = useLatestFunc(onCellContextMenu);
const selectHeaderRowLatest = useLatestFunc(selectHeaderRow);
const selectRowLatest = useLatestFunc(selectRow);
const handleFormatterRowChangeLatest = useLatestFunc(updateRow);
const updateRowLatest = useLatestFunc(updateRow);
const setPositionLatest = useLatestFunc(setPosition);
const selectHeaderCellLatest = useLatestFunc(selectHeaderCell);

Expand Down Expand Up @@ -955,7 +955,8 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
const isLastRow = rowIdx === maxRowIdx;
const columnWidth = getColumnWidth(column);
const colSpan = column.colSpan?.({ type: 'ROW', row: getActiveRow() }) ?? 1;
const { insetInlineStart, ...style } = getCellStyle(column, colSpan);
const style = getCellStyle(column, colSpan);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 object

const { insetInlineStart } = style;
const marginEnd = 'calc(var(--rdg-drag-handle-size) * -0.5 + 1px)';
const isLastColumn = column.idx + colSpan - 1 === maxColIdx;
const dragHandleStyle: React.CSSProperties = {
Expand Down Expand Up @@ -1138,7 +1139,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
gridRowStart,
activeCellIdx: isActiveRow ? activeIdx : undefined,
draggedOverCellIdx: getDraggedOverCellIdx(rowIdx),
onRowChange: handleFormatterRowChangeLatest,
onRowChange: updateRowLatest,
setActivePosition: setPositionLatest,
activeCellEditor: getCellEditor(rowIdx),
isTreeGrid
Expand Down Expand Up @@ -1219,7 +1220,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
iterateOverViewportColumnsForRow={iterateOverViewportColumnsForRow}
onColumnResize={handleColumnResizeLatest}
onColumnResizeEnd={handleColumnResizeEndLatest}
onColumnsReorder={onColumnsReorderLastest}
onColumnsReorder={onColumnsReorderLatest}
sortColumns={sortColumns}
onSortColumnsChange={onSortColumnsChangeLatest}
activeCellIdx={
Expand Down
Loading