Repository navigation
Conversation
The `size` middleware caps the panel with an inline `max-height` that stays on the element. When the content grows after the panel was placed, the panel can only grow up to that stale cap, so `flip` keeps measuring a panel that fits and never moves it to the side with more room. Add a middleware before the others that, when the panel has reached its cap, lifts it back to `--anchor-max-height` and re-measures, once per placement. Fixes tailwindlabs#3904 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@jdeff is attempting to deploy a commit to the Tailwind Labs Team on Vercel. A member of the Team first needs to authorize it. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Leaving the panel uncapped and re-measuring it let the full-height panel take part in page layout. Where scrollbars take up space, a panel taller than the page added a page scrollbar, the viewport resize repositioned the panel, the cap removed the scrollbar again, and it looped, resetting the panel's scroll position on every pass. Measure with the panel fixed-positioned, so it stays out of the page's scrollable overflow, put the cap and scroll positions back in the same step, and hand the measured height to `flip` and `size` as explicit rects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes anchored elements staying on a cramped side when their content grows after they open, for example results that load after opening. The panel keeps the height it had while loading and scrolls, and when the content has its own scrolling list you get a scrollbar inside a scrollbar, even though the other side has room for all of it.
The
sizemiddleware caps the panel with an inlinemax-heightthat stays on the element. When the content grows, the panel can only grow up to that cap, so on the next placementflipmeasures a panel that fits and never moves it.Floating UI treats this as the job of the code that writes the cap:
sizeonly reportsavailableHeighttoapply. Its maintainer described this exact cause in floating-ui/floating-ui#2424 and floating-ui/floating-ui#2954, and the fix was the documentedapplypattern (sizedocs):availableHeight >= elements.floating.scrollHeight ? '' : cap. We didn't use that pattern here because it loops on a common Headless UI layout. A panel whose flex child shrinks to the cap (a scrolling body with a footer) has ascrollHeightequal to the cap, so the>=removes the cap, the panel overflows, gets capped again, and repeats. It also replaces--anchor-max-heightwith''.With this PR, a middleware that runs before the others measures the panel under
--anchor-max-heightwhen the panel has reached its cap, and hands that height toflipandsizeas explicit rects (reset: { rects: { reference, floating } }). They place the panel by the height it can actually take:sizerequests its own reset after capping the panel. Without themiddlewareDatacheck, the two would undo each other until Floating UI's reset limit, and the lastflipwould run on capped measurements.--anchor-max-height, soflipnever judges a panel at a height it can't take.position: fixed, lifts the cap, reads the height, and puts the cap, the position and the scroll positions of the panel and anything scrolled inside it back. A first version left the panel uncapped and returnedreset: { rects: true }, which let the full-height panel take part in page layout. Where scrollbars take up space (Windows, Linux, macOS set to always show them), a panel taller than the page added a page scrollbar, the viewport resize repositioned the panel, the cap removed the scrollbar again, and it looped, resetting the panel's scroll position each pass. Fixed positioning keeps the measurement out of the page's scrollable overflow.computePositionruns. A panel at its cap pays one extra layout per placement.anchor="selection"is unchanged. It uses theinnermiddleware instead offlip.On floating-ui/floating-ui#2424 the maintainer also noted that flipping when content changes can feel disorienting, and suggested
fallbackStrategy: 'initialPlacement'for that. Headless UI already usesflip's default best-fit strategy, andautoUpdatealready re-runs it whenever the panel resizes; it just measures the wrong height when it decides. This change doesn't make anything flip that the existing settings wouldn't. It means the decision uses the panel's real height, instead of squeezing the content into the loading state's room with a scrollbar inside a scrollbar.Fixes #3904
Test plan
Added a playground example,
popover/popover-growing-content: a popover 200px above the bottom of the viewport that opens with a loading state, then loads results into a list with its ownmax-h-72scrolling, the same as the reproduction. Measured in Chromium at 1280×800:bottom starttop startThe existing test suite passes (1,068 passed, 30 skipped). jsdom doesn't do layout, so these tests can't cover this.
We've run the same middleware as a
patch-packagepatch on 2.2.10, with browser tests for growing content, flex panels that shrink to the cap, the reset loop, scroll positions surviving a recompute, and a tall panel staying put with scrollbars that take up space (no style changes while idle).