Skip to content

feat(DataGrid): add pinned (sticky/frozen) column support#4671

Draft
Copilot wants to merge 1 commit intodev-v5from
copilot/research-fluentdatagrid-implementation
Draft

feat(DataGrid): add pinned (sticky/frozen) column support#4671
Copilot wants to merge 1 commit intodev-v5from
copilot/research-fluentdatagrid-implementation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 2, 2026

Pull Request

📖 Description

Implements column pinning for FluentDataGrid (#4652). Columns can be frozen to the left or right edge of the grid and remain visible during horizontal scrolling.

API surface

New Pin parameter on ColumnBase<TGridItem> (applies to PropertyColumn, TemplateColumn, SelectColumn):

<div style="overflow-x: auto;">
    <FluentDataGrid Items="@employees" Style="min-width: max-content;">
        <PropertyColumn Title="ID"      Property="@(e => e.Id)"    Width="60px"  Pin="DataGridColumnPin.Left" />
        <PropertyColumn Title="Name"    Property="@(e => e.Name)"  Width="160px" Pin="DataGridColumnPin.Left" />
        <PropertyColumn Title="Dept"    Property="@(e => e.Dept)" />
        <TemplateColumn Title="Actions" Width="120px" Pin="DataGridColumnPin.Right">
            ...
        </TemplateColumn>
    </FluentDataGrid>
</div>

New enum: DataGridColumnPinNone (default) / Left / Right.

Validation (throws ArgumentException)

  • Pinned columns must declare an explicit pixel Width (e.g. "150px"). fr, %, and other units are rejected.
  • Left-pinned columns must be contiguous at the start of the column list — each must immediately follow another left-pinned column or be the very first column.
  • Right-pinned columns must be contiguous at the end of the column list — each must immediately precede another right-pinned column or be the very last column.

This prevents "floating" pinned columns in the middle of the grid.

Internal changes

File Change
ColumnBase.razor.cs Pin public parameter; PinOffsetPx internal property
FluentDataGrid.razor.cs ValidateAndComputePinnedColumns() + ValidatePinnedColumnConstraints() called from FinishCollectingColumns(); ParsePixelWidth() helper
FluentDataGridCell.razor.cs Emits col-pinned-left/col-pinned-right CSS classes; inline position: sticky, left/right offset, z-index: 1 (data cells)
FluentDataGrid.razor.css Background (--fluent-data-grid-pinned-background), separator borders, z-index floors for header/sticky-header intersections
FluentDataGrid.razor.ts UpdatePinnedColumnOffsets() recalculates live pixel offsets from rendered header widths; called on Initialize() and every resize pointer-move

🎫 Issues

Closes #4652

👩‍💻 Reviewer Notes

  • Focus on ValidatePinnedColumnConstraints() in FluentDataGrid.razor.cs — this is where the ordering rules are enforced.
  • UpdatePinnedColumnOffsets() in FluentDataGrid.razor.ts uses offsetWidth in Grid mode and clientWidth in Table mode — consistent with how the existing resize logic elsewhere in that file measures columns.
  • The --fluent-data-grid-pinned-background CSS custom property can be set per-grid to theme the pinned cell background independently of the rest of the grid.
  • Sticky positioning only activates inside a scrollable ancestor; the demo and docs show the required overflow-x: auto wrapper.

📑 Test Plan

13 new tests in FluentDataGridPinnedColumnTests.razor:

  • Default Pin == None
  • Single left/right pin: correct CSS class (col-pinned-left/col-pinned-right) and inline style (position: sticky; left/right: 0px)
  • Two left-pinned columns: cumulative offsets (0px, 100px)
  • Two right-pinned columns: cumulative offsets reversed (0px, 60px)
  • Missing WidthArgumentException
  • Non-px Width (e.g. 1fr) → ArgumentException
  • Left-pinned column not at start → ArgumentException
  • Left-pinned columns non-contiguous → ArgumentException
  • Right-pinned column not at end → ArgumentException
  • Right-pinned columns non-contiguous → ArgumentException
  • Valid mixed layout (left + normal + right) — assertion-based
  • Snapshot test (verified HTML)

All 3099 existing tests continue to pass.

✅ Checklist

General

  • I have added tests for my changes.
  • I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

Component-specific

  • I have added a new component
  • I have added Unit Tests for my new component
  • I have modified an existing component
  • I have validated the Unit Tests for an existing component

MCP Server

  • I have added or updated MCP Server tools/prompts/resources
  • I have added Unit Tests for my MCP Server changes

⏭ Next Steps

  • Consider exposing UpdatePinnedColumnOffsets as a public JS interop method so host apps can trigger a re-sync after programmatic column visibility changes.
  • RTL: left/right offsets are applied directly; verify visually in a full RTL demo once the component ships.

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.

2 participants