Skip to content

[select] Fix scroll height loop#3795

Merged
atomiks merged 5 commits intomui:masterfrom
atomiks:fix/select-align-grow
Jan 28, 2026
Merged

[select] Fix scroll height loop#3795
atomiks merged 5 commits intomui:masterfrom
atomiks:fix/select-align-grow

Conversation

@atomiks
Copy link
Copy Markdown
Contributor

@atomiks atomiks commented Jan 20, 2026

Can't reproduce this at all on our docs (or a simple Vite demo) but in the Stackblitz it's reproducible.

Chrome; browser window height 857px (various smaller values work too)

Master: https://stackblitz.com/edit/43a3dxj7
This PR: https://stackblitz.com/edit/43a3dxj7-tfa2kpiz

Fixes #3789

@atomiks atomiks added component: select Changes related to the select component. type: bug It doesn't behave as expected. labels Jan 20, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jan 20, 2026

commit: fccf7be

@mui-bot
Copy link
Copy Markdown

mui-bot commented Jan 20, 2026

Bundle size report

Bundle Parsed size Gzip size
@base-ui/react 🔺+312B(+0.07%) 🔺+169B(+0.13%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 20, 2026

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit fccf7be
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/697a2e61a61bcf00082f018d
😎 Deploy Preview https://deploy-preview-3795--base-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@atomiks atomiks marked this pull request as ready for review January 20, 2026 01:03
@atomiks atomiks force-pushed the fix/select-align-grow branch from 222444a to 88cc468 Compare January 20, 2026 01:03
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jan 20, 2026

Greptile Summary

Fixed an infinite scroll loop in the select popup component caused by floating-point precision issues during height and scroll calculations. The fix introduces a 1-pixel epsilon constant (SCROLL_EPS_PX) to prevent micro-adjustments from triggering endless recalculations.

Key changes:

  • Added early returns when scroll differences are negligible (≤1px) to avoid unnecessary recalculations
  • Replaced exact equality checks with epsilon-based comparisons for height and scroll calculations
  • Added bounds recomputation after resizing with epsilon validation before setting scrollTop
  • Applied epsilon tolerance to max height detection to prevent false negatives

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix applies a well-established pattern (epsilon-based comparisons) to resolve floating-point precision issues. The 1px epsilon is appropriately small to avoid user-visible changes while being large enough to prevent infinite loops. All changes are localized to the scroll handling logic within a single component.
  • No files require special attention

Important Files Changed

Filename Overview
packages/react/src/select/popup/SelectPopup.tsx Fixes infinite scroll loop by introducing epsilon-based comparisons for floating-point precision

@tcrognon
Copy link
Copy Markdown

tcrognon commented Jan 25, 2026

This is a more widespread bug. The Element scrollHeight, scrollWidth, clientHeight, clientWidth properties are rounded integers, but the scrollTop, scrollLeft properties are not rounded. The math in this repo mixes the two kinds causing results that can be inaccurate by up to one pixel.

The MDN article (https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled) even calls this out and says that the only way to determine if an element is completely scrolled is

Math.abs(element.scrollHeight - element.clientHeight - element.scrollTop) <= 1;

(although I'd use a 2px threshold because I've scrolled to the bottom and had scrollHeight - clientHeight - scrollTop be slightly greater than 1px before, maybe due to browser rounding implementation)

There is at least one other bug caused by this also - data-overflow-x-end/data-overflow-y-end attribute not being removed when completely scrolled and the viewport width/height is not an integer.

So it would be nice to have a more general solution.

@atomiks
Copy link
Copy Markdown
Contributor Author

atomiks commented Jan 26, 2026

@tcrognon can you make an issue for Scroll Area? The Select popup scroll logic is self contained and doesn't affect other components

@atomiks atomiks force-pushed the fix/select-align-grow branch 5 times, most recently from 9413071 to 488292e Compare January 28, 2026 12:33
@atomiks atomiks force-pushed the fix/select-align-grow branch 5 times, most recently from 8acc7c3 to b0ef626 Compare January 28, 2026 14:51
@atomiks atomiks force-pushed the fix/select-align-grow branch from b0ef626 to 9a12671 Compare January 28, 2026 15:12
@atomiks atomiks merged commit c54f640 into mui:master Jan 28, 2026
23 checks passed
@atomiks atomiks deleted the fix/select-align-grow branch January 28, 2026 15:49
@mitchlloyd
Copy link
Copy Markdown

Thanks for fixing this @atomiks! I'm excited to go back to the OSX style select drop downs in my app. One thing I missed drawing attention to was the font-size: 87.5%; CSS property in the StackBlitz that likely helped expose pixel rounding issues.

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

Labels

component: select Changes related to the select component. type: bug It doesn't behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Select popover growth feedback loop

5 participants