Skip to content

Freeze right columns #1059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

Conversation

MMihran
Copy link

@MMihran MMihran commented Jun 22, 2025

This MR adds support for freezing columns on the right side.
It used draft MR #973 as a base, with major fixes and improvements:

  • Corrected column positioning calculations
  • Fixed hover states
  • Fixed scroll shadows
  • Added handling for column groupings

This addresses the right-side freeze column feature requested in multiple issues: #469, #522, #919, and #957.
The API remains backward compatible, following the proposal here by @jassmith:

interface DataEditorProps {
    // ...
    freezeColumns: number | [left: number, right: number];
}

@MMihran MMihran force-pushed the freeze-right-columns branch 2 times, most recently from 17d0bf2 to f378e2e Compare June 22, 2025 14:08
@lukasmasuch lukasmasuch requested a review from Copilot June 24, 2025 23:15
Copilot

This comment was marked as outdated.

@@ -70,7 +70,7 @@ export interface DataGridProps {

readonly accessibilityHeight: number;

readonly freezeColumns: number;
readonly freezeColumns: number | [left: number, right: number];
Copy link
Contributor

Choose a reason for hiding this comment

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

For a stricter type definition, I suggest using the readonly flag here.

Suggested change
readonly freezeColumns: number | [left: number, right: number];
readonly freezeColumns: number | readonly [left: number, right: number];

Copy link
Author

Choose a reason for hiding this comment

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

Added, thanks for the suggestion!

@MMihran MMihran force-pushed the freeze-right-columns branch from f378e2e to f38bcec Compare July 3, 2025 14:31
@MMihran
Copy link
Author

MMihran commented Jul 3, 2025

Pushed a few updates and rebased with main.

  • Added a comment suggested by Copilot db618f6
  • Marked the freezeColumns tuple as readonly 2196947
  • While testing, we identified and an issue related to the scrollTo function, which is fixed f38bcec

cc: @citizensas

@lukasmasuch lukasmasuch requested a review from Copilot July 10, 2025 18:44
Copilot

This comment was marked as outdated.

Copy link
Collaborator

@BrianHung BrianHung left a comment

Choose a reason for hiding this comment

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

Overall, LGTM. Would update API.md and look at the possible off by one, but merge-able! Thanks 😎

frozenLeftWidth += columns[i].width;
}
let frozenRightWidth = 0;
for (let i = columns.length - 1; i >= columns.length - 1 - freezeRightColumns; i--) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be i >= columns.length - freezeRightColumns? Possible off-by-one error.

Copy link
Author

Choose a reason for hiding this comment

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

Yep, changed, thanks for the catch!

Comment on lines 406 to 407
const freezeLeftColumns = typeof freezeColumns === "number" ? freezeColumns : freezeColumns[0];
const freezeRightColumns = typeof freezeColumns === "number" ? 0 : freezeColumns[1];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Might be worth extracting into helper util if we use it so many times.

Copy link
Author

Choose a reason for hiding this comment

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

Done, thank you

const gridSelection = gridSelectionIn ?? gridSelectionInner;

const spans = React.useMemo(() => {
const result: [number, number][] = [];
let current: [number, number] = [-1, -1];
let lastGroup: string | undefined;
for (let i = freezeColumns; i < columnsIn.length; i++) {
for (let i = freezeColumnsLeft as number; i < columnsIn.length - freezeColumnsRight; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would cast as number above ^

Copy link
Author

Choose a reason for hiding this comment

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

Changed, thank you

@MMihran MMihran force-pushed the freeze-right-columns branch from 0529640 to 67a8c55 Compare August 8, 2025 08:19
@lukasmasuch lukasmasuch requested a review from Copilot August 14, 2025 11:07
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for freezing columns on the right side of the data grid. It extends the freezeColumns API to accept either a number (for backward compatibility) or a tuple [left: number, right: number] to support both left and right column freezing.

  • Introduces right-side column freezing functionality to complement existing left-side freezing
  • Updates rendering logic to handle positioning, clipping, and styling for right-frozen columns
  • Adds comprehensive test coverage for the new freeze behavior

Reviewed Changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/core/src/common/utils.tsx Adds utility function to normalize freeze column parameter
packages/core/src/internal/data-grid/render/ Updates rendering functions to handle right-frozen columns
packages/core/src/internal/data-grid/data-grid.tsx Modifies main data grid component to support new freezing logic
packages/core/src/data-editor/data-editor.tsx Updates data editor to handle right-frozen columns in various operations
Test files Adds comprehensive test coverage for right column freezing

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

cb: WalkColsCallback
): void {
let x = 0;
let clipX = 0; // this tracks the total width of sticky cols
const drawY = totalHeaderHeight + translateY;
for (const c of effectiveCols) {
const clipXRight = freezeTrailingColumns === 0 ? 0 : effectiveCols.slice(-freezeTrailingColumns).reduce((acc, col) => acc + col.width, 0);
Copy link
Preview

Copilot AI Aug 14, 2025

Choose a reason for hiding this comment

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

The slice(-freezeTrailingColumns).reduce() operation is called on every walkColumns invocation. Consider calculating this value once and passing it as a parameter to avoid repeated array operations.

Copilot uses AI. Check for mistakes.

cb: WalkGroupsCallback
): void {
let x = 0;
let clipX = 0;
for (let index = 0; index < effectiveCols.length; index++) {

const effectiveColsRight = freezeTrailingColumns === 0 ? [] : effectiveCols.slice(-freezeTrailingColumns);
Copy link
Preview

Copilot AI Aug 14, 2025

Choose a reason for hiding this comment

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

Similar to the previous issue, the slice operation for right columns is repeated. This could be optimized by calculating once and reusing.

Copilot uses AI. Check for mistakes.

@@ -332,6 +347,25 @@ export function drawGridLines(
}
}

width = Math.min(width, effectiveWidth);
let rightX = width + 0.5;
Copy link
Preview

Copilot AI Aug 14, 2025

Choose a reason for hiding this comment

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

[nitpick] Mutating the width parameter could lead to confusion. Consider using a local variable with a descriptive name like 'clippedWidth' instead of overwriting the parameter.

Suggested change
let rightX = width + 0.5;
const clippedWidth = Math.min(width, effectiveWidth);
let rightX = clippedWidth + 0.5;

Copilot uses AI. Check for mistakes.

groupHeaderHeight
);

width += w;
Copy link
Preview

Copilot AI Aug 14, 2025

Choose a reason for hiding this comment

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

[nitpick] The width parameter is being mutated within the walkGroups function, which could cause confusion since width is typically expected to be read-only. Consider using a local variable to track position changes.

Suggested change
width += w;
currentWidth += w;

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants