Skip to content

fix(react-stately): set allowOverflow on TableLayout nodes for sticky columns - #10528

Open
sundeep8967 wants to merge 1 commit into
adobe:mainfrom
sundeep8967:fix/table-layout-sticky-column-overflow-10518
Open

fix(react-stately): set allowOverflow on TableLayout nodes for sticky columns#10528
sundeep8967 wants to merge 1 commit into
adobe:mainfrom
sundeep8967:fix/table-layout-sticky-column-overflow-10518

Conversation

@sundeep8967

Copy link
Copy Markdown

Description

TableLayout exposes isStickyColumn() as a protected extension point to configure sticky columns. While overriding it sets LayoutInfo.isSticky and maintains persisted indices, TableLayout previously never set LayoutInfo.allowOverflow = true on its layout nodes.

As a result, in VirtualizerItem (layoutInfoToStyle), sticky column cells were clipped and offset by parent scroll coordinates rather than remaining visually pinned in the viewport during virtualized horizontal scrolling.

Solution

Updated TableLayout.ts across buildTableHeader, buildHeaderRow, buildColumn, buildRow, and buildCell to set allowOverflow = true, bringing TableLayout in line with sibling layouts (ListLayout, GridLayout, WaterfallLayout).

Fixes #10518

@snowystinger

Copy link
Copy Markdown
Member

Can you explain this in more depth?

bringing TableLayout in line with sibling layouts (ListLayout, GridLayout, WaterfallLayout)

When do those other layouts use isSticky? or why and when do they set allowOverflow true? Does it truly make sense for every node in TableLayout to now allowOverflow?

… columns

Fixes adobe#10518 by setting allowOverflow = true across TableLayout nodes
(header, headerrow, column, row, cell), ensuring that columns marked
as sticky via isStickyColumn() are not clipped during virtualized scroll.

Signed-off-by: sundeep8967 <sundeep8967@gmail.com>
@sundeep8967
sundeep8967 force-pushed the fix/table-layout-sticky-column-overflow-10518 branch from 3f9e695 to 7c86e7f Compare September 5, 2026 09:42
@sundeep8967

Copy link
Copy Markdown
Author

Hi @snowystinger,

Thanks for the question!

Here is the exact mechanism and context:

The allowOverflow & isSticky interaction in VirtualizerItem

In react-aria's VirtualizerItem.mjs (layoutInfoToStyle), the position and CSS overflow styles for virtualized items are calculated as:

top: layoutInfo.rect.y - (parent && !(parent.allowOverflow && layoutInfo.isSticky) ? parent.rect.y : 0),
[xProperty]: layoutInfo.rect.x - (parent && !(parent.allowOverflow && layoutInfo.isSticky) ? parent.rect.x : 0),
position: layoutInfo.isSticky ? 'sticky' : 'absolute',
overflow: layoutInfo.allowOverflow ? 'visible' : 'hidden',

Notice two critical points:

  1. When a column or cell is sticky (layoutInfo.isSticky = true), its x/top coordinates are calculated relative to the un-offset coordinate space only when parent.allowOverflow is true. Otherwise, it subtracts parent.rect.x/parent.rect.y, offsetting the sticky node by the parent's coordinates.
  2. Because virtualizer wrapper nodes default to overflow: hidden, any parent node without allowOverflow = true clips its child sticky cells as the row/header scrolls horizontally, causing the sticky cell to scroll out of view instead of remaining pinned to the viewport.

Sibling Layouts

In ListLayout (line 221), GridLayout (line 106), and WaterfallLayout (line 90), allowOverflow = true is set on layout items (e.g. for section headers in ListLayout that use isSticky).

Scoping allowOverflow in TableLayout

In TableLayout, setting allowOverflow = true broadly on rows and headers allows child cells and columns with isSticky = true to render without clipping and compute their un-offset sticky positions properly.

However, if you'd prefer not to set allowOverflow = true unconditionally on all table nodes, we can easily scope it:

  • Set row.allowOverflow = true and headerRow.allowOverflow = true only if this.stickyColumnIndices.size > 0 (or if any column in that row satisfies this.isStickyColumn(col)).

Let me know if you would prefer this scoped approach and I'd be happy to update the PR!

@snowystinger

Copy link
Copy Markdown
Member

Hey, so AI is leading you a little astray here. The reason for the overflow being hidden is that it is a performance optimisation.

That particular optimisation is a little dated now however, we're discussing if we still need this at all.

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.

TableLayout.isStickyColumn() never sets allowOverflow, so a sticky column can't actually stick during virtualized horizontal scroll

2 participants