Frontmatter
| id | 9458 |
| title | Grid: Create Main Thread Addon for Column Pinning (CSS Variables) |
| state | Closed |
| labels | enhancementaigrid |
| assignees | tobiu |
| createdAt | Mar 13, 2026, 11:27 AM |
| updatedAt | Mar 16, 2026, 12:49 PM |
| githubUrl | https://github.com/neomjs/neo/issues/9458 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | 9456 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Mar 16, 2026, 12:49 PM |
Grid: Create Main Thread Addon for Column Pinning (CSS Variables)
tobiu added parent issue #9456 on Mar 13, 2026, 11:27 AM
tobiu assigned to @tobiu on Mar 13, 2026, 11:27 AM

tobiu
Mar 16, 2026, 12:48 PM
Input from Gemini 3.1 Pro:
✦ I have completed the implementation for this sub-task (#9458). We extended the scope to make the addon registration dynamic, ensuring zero overhead for grids without locked columns.
Implementation Details:
GridColumnScrollPinningAddon:
- Created
src/main/addon/GridColumnScrollPinning.mjs.- Listens to horizontal
scrollevents on the Grid Container wrapper node.- Synchronously calculates
startOffset(scrollLeft) andendOffset(scrollLeft - (scrollWidth - clientWidth)).- Applies these as CSS custom properties (
--grid-locked-start-offset,--grid-locked-end-offset) directly to the container node. Since CSS variables inherit, this single DOM write efficiently provides the translation offsets to all locked header buttons and grid cells.Dynamic Lifecycle (
GridContainer&ScrollManager):
- Added a
hasLockedColumnsgetter togrid.Container.mjsto dynamically evaluate if any column is currently locked ('start'or'end'). Removed theleft/rightaliases to strictly enforce logical, RTL-ready terminology.- Refactored
grid.ScrollManager.mjsto dynamically register/unregister the addon viaupdateColumnScrollPinningAddon(active).- The ScrollManager now actively evaluates
me.mounted && me.gridContainer?.hasLockedColumnsduringafterSetMounted,afterSetWindowId, and when explicitly triggered by the Container'sonColumnLockChangepipeline.- This architecture guarantees that the scroll listener and math calculations are strictly isolated to grids that actually require pinning, scaling perfectly down to zero cost for standard grids.
tobiu closed this issue on Mar 16, 2026, 12:49 PM
tobiu cross-referenced by #9456 on Mar 16, 2026, 1:25 PM
This is a sub-task of Epic #9456 (Buffered Grid - High-Performance Locked Columns).
Context: To achieve 60fps horizontal scrolling without tearing or "catch up" visual artifacts, the pinning of locked columns must be handled synchronously in the Main Thread. Iterating over cell DOM nodes to apply transforms within a scroll loop is too expensive.
Task:
Neo.main.addon.GridColumnScrollPinning.GridRowScrollPinning. It should listen to the horizontalscrollevent of the Grid Wrapper/Container.--grid-locked-start-offset: ${scrollLeft}px;--grid-locked-end-offset: ${scrollLeft - (scrollWidth - clientWidth)}px;src/grid/ScrollManager.mjs, ensuring it is properly managed during grid lifecycle events (mount/destroy).Note: The offset calculation logic cleanly handles scaling without requiring knowledge of the specific column widths or positions.