Skip to content

fix(select): keep scroll position when scrolling content with scroll buttons#3978

Open
thatssoheil wants to merge 1 commit into
radix-ui:mainfrom
thatssoheil:fix/select-scroll-button-jump
Open

fix(select): keep scroll position when scrolling content with scroll buttons#3978
thatssoheil wants to merge 1 commit into
radix-ui:mainfrom
thatssoheil:fix/select-scroll-button-jump

Conversation

@thatssoheil

Copy link
Copy Markdown

Problem

When a Select renders Select.ScrollUpButton / Select.ScrollDownButton, scrolling the open listbox with the pointer, wheel, or touch snaps the viewport back to the selected item once you reach the top or bottom of the list. Without the scroll buttons, scrolling works as expected.

Fixes #3686.

Cause

The scroll buttons mount and unmount as the user scrolls across the top/bottom thresholds (SelectScrollUpButton only renders while scrollTop > 0, SelectScrollDownButton only while not at the bottom). On every mount, SelectScrollButtonImpl ran a useLayoutEffect that called scrollIntoView({ block: 'nearest' }) on document.activeElement — which in an open Select is the selected item. So each remount during a manual scroll yanked the (just-scrolled-away) selected item back into view.

That compensation exists for a reason: when a scroll button first appears it consumes vertical space, which during keyboard navigation could push the active item partly out of view.

Fix

Only re-run the compensation when keyboard focus has moved to a different item. Keyboard navigation moves document.activeElement; pointer/wheel/touch scrolling does not. The "last scrolled-into-view item" is tracked via a ref lifted into the content context (mirroring the existing searchRef / shouldExpandOnScrollRef pattern) so it survives the scroll buttons remounting.

  • Keyboard nav → focus changes → still compensates (behavior unchanged).
  • Pointer / wheel / touch → focus stays on the selected item → no snap-back.

Tests

Added a CypressScrollButtons story and two e2e tests in Select.cy.ts:

  • manual scrolling does not snap the selected item back into view, and
  • keyboard navigation still keeps the focused item within the viewport.

Local checks pass: tsc --noEmit, oxlint, and the existing Select unit suite (7/7). The new behavior is covered by the Cypress e2e (run in CI). Changeset included (patch).


🤖 Drafted with AI assistance (Claude); reviewed, tested, and owned by me.

…buttons

When Select.ScrollUpButton/Select.ScrollDownButton are present, the buttons
mount and unmount as the user scrolls across the top/bottom thresholds. Each
mount re-ran scrollIntoView on the focused (selected) item, snapping the
viewport back mid-scroll. The compensation now only runs when keyboard focus
moves to a different item, so pointer/wheel/touch scrolling is left alone while
keyboard navigation still keeps the active item visible.

Fixes radix-ui#3686

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 25, 2026 14:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 78feb7b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@radix-ui/react-select Patch
radix-ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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.

[Select] Scroll jumping to the selected item when reaching start or end of the list with Select.ScrollUpButton and Select.ScrollDownButton present

2 participants