Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
321aeb1
Update release.js.yml
rahulyadav5524 Jul 1, 2024
970e725
Added feature to right side freeze columnj
rahulyadav5524 Jul 1, 2024
dbc629d
revert workflow file
rahulyadav5524 Jul 1, 2024
73a7e6c
fixed selection issue and highlight fixes
rahulyadav5524 Jul 2, 2024
fb2abf5
freeze right columns: calculations, hovers, groupings and shadows
Jun 22, 2025
e245c1a
added an inline comment explaining freezeColumnsLeft and freezeColumn…
Jul 3, 2025
9033b8a
added readonly flag to freezeColumns tuple prop
Jul 3, 2025
9a65fc0
fix scrollTo issue not finding a column
Jul 3, 2025
c65fe42
fix image loader doesn't take into account freezeColumns new api
Jul 8, 2025
e89d0f8
fix vertical lines calculation issue
Jul 15, 2025
9d03654
add utility function to extract left and right freeze, minor fixes
Aug 8, 2025
2cc2935
apply minor code review impovements
Aug 20, 2025
388eafc
fix: ensure freeze columns cannot exceed total column count
Aug 22, 2025
67196ea
update API.md with new freezeColumns api
Dec 18, 2025
a5c32ac
fix: add keyboard support for context menu
Jan 26, 2026
80d78d3
add unit tests
Jan 27, 2026
9684027
Merge remote-tracking branch 'origin/freeze-right-columns' into pre-r…
citizensas Jan 29, 2026
408a543
Merge remote-tracking branch 'origin/fix-context-menu-keyboard-suppor…
citizensas Jan 29, 2026
4031bf3
fix: add keyBinding for context menu
Feb 2, 2026
20afebe
resolve comments
Feb 3, 2026
aa8e457
fix spacing
Feb 3, 2026
8b65628
fix lint
Feb 3, 2026
b7b2ef2
Merge branch 'fix-context-menu-keyboard-support' into pre-release
Feb 4, 2026
1b69a25
fix: repaint per-column fill for spanning cells in frozen trailing rows
Jul 3, 2026
48ec0d1
fix: repaint per-column fill for spanning cells in frozen trailing rows
Jul 3, 2026
7896e72
fix(data-grid): prevent scroll rows from bleeding frozen band
Jul 13, 2026
b5c5d40
Merge branch 'fix/frozen-row-span-overflow' into pre-release
Jul 13, 2026
4114048
fix: don't block editOnType for cells inside frozen regions
Aug 10, 2026
e2d1961
fix: reset isActivelyDraggingHeader and scrollDir on native dragend
Aug 14, 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
26 changes: 14 additions & 12 deletions packages/core/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,9 @@ or you can create a portal element yourself using the `createPortal` function fr
```jsx
const portalRef = useRef(null);
<>
{
createPortal(
<div ref={portalRef} style="position: fixed; left: 0; top: 0; z-index: 9999;" />,
document.body
)
}
<DataEditor width={500} height={300} portalElementRef={portalRef} {...props} />
</>
{createPortal(<div ref={portalRef} style="position: fixed; left: 0; top: 0; z-index: 9999;" />, document.body)}
<DataEditor width={500} height={300} portalElementRef={portalRef} {...props} />
</>;
```

Once you've got that done, the easiest way to use the Data Grid is to give it a fixed size:
Expand Down Expand Up @@ -87,10 +82,10 @@ All data grids must set these props. These props are the bare minimum required t
Most data grids will want to set the majority of these props one way or another.

| Name | Description |
|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [fixedShadowX](#fixedshadow) | Enable/disable a shadow behind fixed columns on the X axis. |
| [fixedShadowY](#fixedshadow) | Enable/disable a shadow behind the header(s) on the Y axis. |
| [freezeColumns](#freezecolumns) | The number of columns which should remain in place when scrolling horizontally. The row marker column, if enabled is always frozen and is not included in this count. |
| [freezeColumns](#freezecolumns) | The number of columns which should remain in place when scrolling horizontally, or a tuple `[left, right]` to freeze columns on both sides. The row marker column, if enabled is always frozen and is not included in this count. |
| [getCellsForSelection](#getcellsforselection) | Used to fetch large amounts of cells at once. Used for copy/paste, if unset copy will not work. |
| [markdownDivCreateNode](#markdowndivcreatenode) | If specified, it will be used to render Markdown, instead of the default Markdown renderer used by the Grid. You'll want to use this if you need to process your Markdown for security purposes, or if you want to use a renderer with different Markdown features. |
| [onVisibleRegionChanged](#onvisibleregionchanged) | Emits whenever the visible rows/columns changes. |
Expand Down Expand Up @@ -192,7 +187,7 @@ Most data grids will want to set the majority of these props one way or another.
| [onRowMoved](#onrowmoved) | Emitted when a row has been dragged to a new location. |
| [preventDiagonalScrolling](#preventdiagonalscrolling) | Prevents diagonal scrolling |
| [rowSelectionMode](#rowselectionmode) | Determines if row selection requires a modifier key to enable multi-selection or not. |
| [columnSelectionMode](#columnselectionmode) | Determines if column selection requires a modifier key to enable multi-selection or not. |
| [columnSelectionMode](#columnselectionmode) | Determines if column selection requires a modifier key to enable multi-selection or not. |
| [scrollToEnd](#scrolltoend) | When set to true, the grid will scroll to the end. The ref has a better method to do this and this prop should not be used but it will remain supported for the foreseeable future. |
| [showMinimap](#showminimap) | Shows the interactive minimap of the grid. |
| [validateCell](#validatecell) | When returns false indicates to the user the value will not be accepted. When returns a new GridCell the value is coerced to match. |
Expand Down Expand Up @@ -550,11 +545,18 @@ getCellContent: (cell: Item) => GridCell;
## freezeColumns

```ts
freezeColumns?: number;
freezeColumns?: number | readonly [left: number, right: number];
```

Set to a positive number to freeze columns on the left side of the grid during horizontal scrolling.

Alternatively, pass a tuple `[left, right]` where:

- `left` is the number of columns to freeze on the left side
- `right` is the number of columns to freeze on the right side

Note: The row marker column, if enabled, is always frozen and is not included in the left freeze count.

---

## getCellsForSelection
Expand Down
15 changes: 12 additions & 3 deletions packages/core/src/common/render-state-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,42 @@ export abstract class WindowingTrackerBase {
height: 0,
};

public freezeCols: number = 0;
public columnsLength: number = 0;
public freezeCols: number | readonly [number, number] = 0;
public freezeRows: number[] = [];

protected isInWindow = (packed: number) => {
const freezeColumnsLeft = typeof this.freezeCols === "number" ? this.freezeCols : this.freezeCols[0];
const freezeColumnsRight = typeof this.freezeCols === "number" ? 0 : this.freezeCols[1];
const col = unpackCol(packed);
const row = unpackRow(packed);
const w = this.visibleWindow;
const colInWindow = (col >= w.x && col <= w.x + w.width) || col < this.freezeCols;
const colInWindow =
(col >= w.x && col <= w.x + w.width) ||
col < freezeColumnsLeft ||
col > this.columnsLength - freezeColumnsRight - 1;

const rowInWindow = (row >= w.y && row <= w.y + w.height) || this.freezeRows.includes(row);
return colInWindow && rowInWindow;
};

protected abstract clearOutOfWindow: () => void;

public setWindow(newWindow: Rectangle, freezeCols: number, freezeRows: number[]): void {
public setWindow(newWindow: Rectangle, freezeCols: number, freezeRows: number[], columnsLength: number): void {
if (
this.visibleWindow.x === newWindow.x &&
this.visibleWindow.y === newWindow.y &&
this.visibleWindow.width === newWindow.width &&
this.visibleWindow.height === newWindow.height &&
this.freezeCols === freezeCols &&
this.columnsLength === columnsLength &&
deepEqual(this.freezeRows, freezeRows)
)
return;
this.visibleWindow = newWindow;
this.freezeCols = freezeCols;
this.freezeRows = freezeRows;
this.columnsLength = columnsLength;
this.clearOutOfWindow();
}
}
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/common/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,10 @@ export function useDeepMemo<T>(value: T): T {

return ref.current;
}

export function normalizeFreezeColumns(freezeColumns: number | readonly [number, number]): readonly [number, number] {
const freezeLeftColumns = typeof freezeColumns === "number" ? freezeColumns : freezeColumns[0];
const freezeRightColumns = typeof freezeColumns === "number" ? 0 : freezeColumns[1];

return [freezeLeftColumns, freezeRightColumns];
}
4 changes: 4 additions & 0 deletions packages/core/src/data-editor/data-editor-keybindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export interface ConfigurableKeybinds {
readonly selectAll: Keybind;
readonly selectRow: Keybind;
readonly selectColumn: Keybind;

readonly contextMenu: Keybind;
}

export type Keybinds = ConfigurableKeybinds & ForcedKeybinds & Partial<BackCompatKeybinds>;
Expand Down Expand Up @@ -118,6 +120,7 @@ export const keybindingDefaults: Keybinds = {
selectGrowRight: true,
selectGrowDown: true,
selectGrowLeft: true,
contextMenu: true,
};

function realizeKeybind(keybind: Keybind, defaultVal: string): string {
Expand Down Expand Up @@ -174,6 +177,7 @@ export function realizeKeybinds(keybinds: Keybinds): RealizedKeybinds {
selectToLastCell: realizeKeybind(keybinds.selectToLastCell, "primary+shift+End"),
selectToLastColumn: realizeKeybind(keybinds.selectToLastColumn, "primary+shift+ArrowRight"),
selectToLastRow: realizeKeybind(keybinds.selectToLastRow, "primary+shift+ArrowDown"),
contextMenu: realizeKeybind(keybinds.contextMenu, "shift+F10"),
};
}

Expand Down
Loading
Loading