feat(grid)!: replace frozen panes with pinning and sticky docking - #2782
Draft
ghiscoding wants to merge 124 commits into
Draft
ghiscoding wants to merge 124 commits into
ghiscoding wants to merge 124 commits into
Conversation
ghiscoding
marked this pull request as draft
September 8, 2026 01:17
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2782 +/- ##
=========================================
Coverage 100.0% 100.0%
=========================================
Files 199 200 +1
Lines 25868 27035 +1167
Branches 9177 9501 +324
=========================================
+ Hits 25868 27035 +1167
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
angular-slickgrid
aurelia-slickgrid
slickgrid-react
slickgrid-vue
@slickgrid-universal/angular-row-detail-plugin
@slickgrid-universal/aurelia-row-detail-plugin
@slickgrid-universal/react-row-detail-plugin
@slickgrid-universal/vue-row-detail-plugin
@slickgrid-universal/binding
@slickgrid-universal/common
@slickgrid-universal/composite-editor-component
@slickgrid-universal/custom-footer-component
@slickgrid-universal/custom-tooltip-plugin
@slickgrid-universal/empty-warning-component
@slickgrid-universal/event-pub-sub
@slickgrid-universal/excel-export
@slickgrid-universal/graphql
@slickgrid-universal/odata
@slickgrid-universal/pagination-component
@slickgrid-universal/pdf-export
@slickgrid-universal/row-detail-view-plugin
@slickgrid-universal/rxjs-observable
@slickgrid-universal/sql
@slickgrid-universal/text-export
@slickgrid-universal/utils
@slickgrid-universal/vanilla-bundle
@slickgrid-universal/vanilla-force-bundle
@slickgrid-universal/web-mcp
commit: |
Owner
Author
Sticky Columns / RowsScreencast_20260903_184235.webmPinning Columns / RowsScreencast_20260910_223012-1.webmScreencast_20260911_013813.webm |
…all frozen/freeze wording
ghiscoding
force-pushed
the
feat/pinning-and-sticky
branch
from
September 9, 2026 13:41
cefcc2e to
96b1d94
Compare
Docking has one horizontal scroll owner: the proxy scrollbar. The row and chrome transforms in the native-scroll fallback are unreachable whenever docking is configured, because the proxy scrollbar is introduced and removed with the docking layout. Remove those helpers and their call sites, retaining the proxy CSS offset and full-width-group transform. Remove unit assertions for the retired fallback while preserving proxy-scroll and docking-region coverage.
Three pinning validation sites shared the same alert-once behavior, differing only in callback and message. Route each rejection through one helper so callers that force an alert still get one, while render-time validation stays quiet after the first alert.
Full-width group cells already consume the published horizontal scroll offset through the docking stylesheet, so remove the per-row inline transform scan. Group the shared pinned and sticky edge separator declarations while preserving their selector specificity and left/right shadows. Port of 6pac/SlickGrid@d17e104.
Resolve contested sticky columns with one trailing-edge map and a leading-edge filter, avoiding repeated findIndex and splice operations while preserving edge preference and tie behavior. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…a resize When a column resize changes whether the proxy scrollbar reserves layout height, resize the canvas on that transition so the viewport stays flush with the track. Track the reservation through its existing dimension update and guard the resize against re-entry. Add unit coverage for scrollbar appearance, removal, stable overflow, and the re-entry guard. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Firefox on Linux can report a zero-width overlay scrollbar even though the visible scrollbar occupies a narrow strip. The docked-row overlay then clips to the viewport edge and paints over the scrollbar in pinned sections. Add an 8px clip inset only for Firefox/Linux when a vertical scrollbar is present and its measured width is zero. Keep the existing geometry for other browsers and for scrollbars with a measurable width.
Move the docked-row overlay inside the vertical viewport as a zero-height sticky layer. This lets Firefox paint its native scrollbar above pinned rows, so the scrollbar spans the pinned sections without clipping their right edge. Remove the Firefox-specific scrollbar-width inset and clip-path workaround. Use the viewport’s height for docked-row synchronization and bottom-row positioning, since the overlay itself no longer has height. Co-authored-by: ChatGPT <noreply@openai.com>
Resolve pinned and sticky columns along the logical inline axis so leading and trailing bands mirror correctly in RTL. Keep docked rows and proxy scrolling aligned with the RTL viewport.\n\nDemonstrate pinned columns and top/bottom docked rows in the Vanilla and framework RTL examples, and document the mirrored pinning semantics.
…eation Demonstrate a colspan crossing from the leading pinned band into scrolling columns across Vanilla and framework RTL examples, with coverage for its seam and hit-testing.\n\nIgnore runtime rtl changes in setOptions so the initialized DOM direction cannot diverge from docking geometry.
Prevent transformed header content from appearing above the vertical scrollbar when pinning or sticky columns are enabled. The grid now measures the body scrollbar width and overlays that strip across the affected header containers. Added regression coverage and documentation.
Synchronize body-cell geometry and sticky transforms while resizing columns so header and cell positions remain aligned without requiring a scroll event. Preserve Grid Menu scrollbar-cover behavior and add regression coverage for sticky column resizing.
… grids in a right-to-left grid the separator of a pinned band was on the wrong side of its edge column, so the band looked one column off. Every docking separator is an inset box-shadow with a physical offset: -1px draws it on the right edge and +1px on the left, which is the inner edge only when reading left to right. The offsets are now multiplied by --slick-docking-direction, which the grid already sets to 1 or -1, so the separator faces the scrolling columns in both directions. Left to right, the computed values do not change. A docked sticky column becomes the band edge, and its header cell gets slick-column-sticky-left-edge or -right-edge. No rule styled those classes, so the header lost its separator when a sticky column docked, in both directions. They now share the header rules of the pinned edges. The new case in example-pinning-rtl.cy.ts checks that every separator faces the scrolling columns, before and after the sticky column docks. It fails on 7d9555c and passes with this change. example-sticky-financial-report.cy.ts also checks the header separator at the initial viewport. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restore fork-compatible band-relative positioning for colspan continuation fragments in LTR and RTL grids. Remove the extra proxy transform that caused fragments to drift while scrolling, and update pinning unit expectations.
Description: Skip grouped-header synchronization when the horizontal offset is unchanged, and reuse pinned-column width measurements until the rendered layout changes or columns are resized. Remove a duplicate pinning-menu cleanup call. Add focused coverage for scroll and resize behavior. Validation: Header grouping spec passes (16 tests); line coverage is 100%. Prettier and diff checks pass.
…mn docks In the body, the last permanently pinned cell always draws the band's separator, and a docked sticky cell draws its own further in. The header instead moved its one separator from the pinned column to the sticky column, so with a sticky column docked next to permanent pins the body showed two lines and the header one. The header's pinned edge is now the last permanently pinned column of each band, as in the body. It no longer changes while scrolling, so updateStickyColumnTransforms() no longer needs the loop that moved it. The new case in example-pinning-rtl.cy.ts checks that every header separator lines up with a body separator, before and after the sticky column docks. It fails without this change: 2 header separators against 3 in the body. The far-right test in example-sticky-financial-report.cy.ts asserted the state from before the scroll. Q3, Q4 and YTD are sticky at scroll 0, and cy.scrollTo() may not deliver a scroll event before the assertions run. The test now checks the far-right state, which is false before the scroll: Q3, Q4 and YTD are released, and Q2 is the edge of the left band, with its separator in the header and in the body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…says A permanently pinned column that also carried `sticky` was routed onto the sticky transform path by sites that read the column flag alone, while the docking layout kept it in its permanent band. Its header, filter cell, and body cells must all stay in that band. One predicate, isStickyTransformColumn(), now decides the path for cells, chrome, region sync, and sticky transforms: a pinned column is never a sticky candidate. The focused unit regression covers boundary pinning, column pinning at runtime, and the rendered body and header. It fails on the previous implementation for those cases.
…hidden-column scan scrollToX() now publishes the shared horizontal offset variable directly; the per-column proxy transform writes had no effect because the stylesheet consumes that variable. updateColumnPositionCaches() now resolves each hidden-column block once instead of rescanning it for every hidden column. Remove the class-keyed measurement cache, which did not hit because filter and footer cells have per-column classes, and remove the unused frozen-pane height fields. appendColspanFragments() reuses the row cached regions. The pinning unit test verifies that scrolling updates the shared variable without rewriting pinned header or filter transforms.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduce a single-viewport docking architecture for permanent pinned columns/rows and
scroll-activated sticky columns/rows.
This is an intentional v11 breaking change. The previous multi-pane frozen implementation has
been removed from the runtime and replaced with one virtualized body viewport, one vertical
scroll owner, one horizontal scroll owner, and stable per-row left/center/right cell regions.
Why
The legacy frozen-pane implementation required multiple synchronized panes and scroll
containers. This increased complexity around scrolling, resizing, virtualization, editing,
grouping, and framework integrations.
The new architecture provides a simpler and more predictable model:
Unlike the previous freeze-until-column/row behavior, users can now pin individual columns or
rows independently. For example, columns 0 and 2 can be pinned while column 1 remains in the
center region.
Changes
GridOption.pinningsupport for:columns.left/columns.right;rows.top/rows.bottom.Column.pinnedandCurrentColumn.pinningstate support.Column.stickyandGridOption.stickyRowsfor scroll-activated docking.DockingControllerfor permanent and sticky column/row resolution.conveyor/clampoverflow strategies.
fragments.
and framework integrations.
Pin Left;Pin Right;Unpin Column;Unpin All Columns.Column.pinnablesupport for controlling Header Menu pinning commands.pinningshape.is intentionally not serialized.
.slick-horizontal-scrollerand.slick-vertical-scrollerselectors.scroll branches, redundant viewport/canvas aliases, and old pane CSS classes.
-1000pxheader coordinate workaround andHEADER_WIDTH_SLACK.pinning-stickyskill as implementation and documentation guidance.Breaking changes
The old frozen-pane configuration and APIs are removed.
The canonical configuration is now:
Legacy flat pinning options and temporary aliases are no longer supported.
Pinning-related state now uses
GridState.pinning.Sticky state is not serialized because it changes with scrolling.
The old multi-pane DOM structure and pane selectors are no longer available.
Column reordering remains within each docking band; moving a column between pinned and center
bands is an explicit pinning operation.
Legacy names and theme variables are retained only as migration documentation references.
References
Ag-Grid Column Pinning was used as key concept reference for the idea of a single horizontal scroller and single vertical scroller, also for its declaration of left/center/right cell docking regions
Validation
The following checks pass:
git diff --check.pinning/sticky, resizing, reordering, RTL, variable row heights, editing, selection,
grouping, spans, and framework parity.
The accessibility audit found no pinning/sticky-specific semantic-tree or keyboard-navigation
regressions. Automated axe/WCAG integration and manual screen-reader validation are not included
in this PR.
Implementation status
The single-viewport rewrite and legacy runtime cleanup are complete. This is no longer a POC
that runs alongside the old frozen-pane implementation.
The approximate library-only production diff is:
+3,989 / -1,550;+2,439net LOC relative to the base commit.These figures exclude demos, tests, generated output, and framework-wrapper changes.
Follow-up work
The following items are intentionally separate from the v11 implementation:
None of these requires restoring the legacy pane architecture or changing the current pinning/sticky
runtime design.
AI / LLM assistance
documentation updates, test maintenance, and validation support.
Checklist
documentation, tests, and cleanup.
TODOs
next-v11