Skip to content

Table keyboard navigation: scrollIntoViewport containingElement centering causes vertical viewport jumps in bounded scroll containers #10196

Description

@les-friesen

Provide a general summary of the issue here

When keyboard-navigating a React Aria Table inside a bounded scroll container (explicit height/maxHeight) with sticky header/column and scroll-padding on the scroll container, scrollIntoViewport can cause sudden vertical viewport jumps even though focus remains on the correct cell.

This is especially visible when:

  • Moving horizontally along a row (ArrowLeft/ArrowRight) — scrollTop changes unexpectedly
  • Moving vertically at the edges (e.g. ArrowUp from the first body row to the column header, ArrowDown near the bottom) — viewport recenters to the middle of the table instead of scrolling one row

Stock RAC Storybook stories without scroll-padding + sticky + bounded vertical scroll do not reproduce the issue.

Screen.Recording.2026-06-12.at.5.03.20.PM.mov

🤔 Expected Behavior?

Keyboard navigation should scroll the bounded container just enough to keep the focused cell visible (respecting scroll-padding), without recentering the entire <table> in the viewport.

😯 Current Behavior

useSelectableCollection calls scrollIntoView(scrollContainer, element) (padding-aware), then scrollIntoViewport(element, { containingElement: table }).

In scrollIntoViewport (@react-aria/utils / react-aria scrollIntoView.ts), after targetElement.scrollIntoView({ block: 'nearest' }), if the cell's bounding rect moved by >1px in either axis, the fallback runs:

containingElement?.scrollIntoView?.({ block: 'center', inline: 'center' });
targetElement.scrollIntoView?.({ block: 'nearest' });

Horizontal keyboard moves change left, which trips this fallback and calls table.scrollIntoView({ block: 'center', ... }), causing unwanted vertical scroll. Vertical edge navigation has the same problem when top changes.

The padding-aware scrollIntoView on the scroll container already positions the cell correctly when scroll-padding accounts for sticky regions.

Repro in StackBlitz: https://stackblitz.com/edit/github-budc6mta-fdxhpe8x?file=src%2Findex.css

💁 Possible Solution

scrollIntoViewport runs a padding-aware scroll on scroll parents, then a native targetElement.scrollIntoView({ block: 'nearest' }), then — if position changed by >1px in either axis — calls containingElement.scrollIntoView({block: 'center', inline: 'center' }). That last step recenters the entire table and causes vertical viewport jumps during horizontal keyboard navigation.

Possible fix:

  1. Skip containingElement centering when the padding-aware scroll parent pass
    already satisfied visibility (especially with scroll-padding for sticky UI).
  2. If a containing-element fallback is still needed, only trigger it when
    vertical position remains unsatisfactory (originalTop vs newTop), not
    when only left changed.

Optional: expose centerContainingElement?: boolean (default false) for consumers who need the legacy behavior.

Related: #8977 (same fallback mechanism, different scroll context).

🔦 Context

We hit this building a Table with sticky header/column and scroll-padding on ResizableTableContainer to keep keyboard focus clear of pinned regions. We worked around it with a yarn patch on react-aria@3.48.0 that removes the containing-element centering fallback.

RAC version: 1.17.0 / react-aria 3.48.0

🖥️ Steps to Reproduce

Render a Table inside ResizableTableContainer with bounded height (e.g. maxHeight: 400px) and overflow: auto
Enable sticky header and/or sticky column
Set scroll-padding-block-start / scroll-padding-inline-start on the scroll container for sticky clearance
Keyboard-focus cells and move horizontally along a row, or ArrowUp/ArrowDown at the top/bottom of the visible area
Observe scrollTop jumping / viewport recentering while focus stays correct

Version

react-aria-components@1.17.0 (react-aria@3.48.0)

What browsers are you seeing the problem on?

Chrome, Safari, Firefox, Microsoft Edge

If other, please specify.

No response

What operating system are you using?

masOS

🧢 Your Company/Team

MaintainX

🕷 Tracking Issue

No response

Activity

  1. les-friesen commented on Jun 12, 2026

    @les-friesen
    Author

    Happy to open a PR for this. Before I do — which direction would you prefer?

    Heuristic fix: skip containingElement centering when padding-aware scroll already satisfied visibility, and only fall back on vertical (top) deltas.
    Explicit opt-out: add centerContainingElement?: boolean (and keep current behavior as default).
    Or a combination of both? I'll wait for your preference before implementing.

  2. nwidynski commented on Jun 12, 2026

    @nwidynski
    Contributor

    Duplicate of #10182?

  3. les-friesen commented on Jun 15, 2026

    @les-friesen
    Author

    Duplicate of #10182?

    Not a strict duplicate, but same underlying issue I think. Ours is vertical jumps from horizontal keyboard nav in a bounded scrollport. Same scrollIntoViewport fallback though, so the scrollIntoViewIfNeeded approach on #10182 should cover this too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions