feat(Combobox): portal + anchor the dropdown menu (Headless UI v2) (MET-3088) - #62
Merged
Merged
Conversation
…-3088) Migrate the Combobox code component from Headless UI v1 to v2 so the dropdown menu is portalled and positioned by Floating UI instead of being an abspos child of the input. This lets the menu escape any `overflow` ancestor (it was previously clipped inside narrow containers, e.g. the Institutional Program Assessment sidebar) and flip/shift to stay in the viewport. - `Combobox.Input/Button/Options/Option` -> v2 named components; drop the `<Transition>` wrapper for the `transition` prop + `[data-closed]`; drop `nullable`; reset the query on `onClose`. - Replace the `arrowIconRef.click()` focus hack with `immediate` (kept a slim `onClick` so re-clicking a focused input reopens the menu). - New `menuWidth` prop: `"input"` (default, unchanged behaviour) or `"fit"` (grows to the widest option, never narrower than the input). `width`/`min-width` are applied inline so they win over a leftover `width` in `optionsClassName`; `max-width` is left to CSS so callers can still cap it. - Split the menu into `.positioner` (what Floating UI portals/positions and stamps an inline `max-width: <viewport>` onto) and an inner `.options` wrapper that carries all author-facing sizing/look, so a caller's `max-width` is no longer overridden. - `anchor` gap of 1px + restored top `clip-path` keep `"input"` mode visually identical to before. - Option-state selectors for `optionClassName` move from `[data-headlessui-state*=active]` etc. to v2's `[data-focus]` / `[data-selected]` / `[data-disabled]`. - Bump the `@headlessui/react` peer range to ^2.2.0 (2.2.x carries the Combobox open-on-trigger and `immediate` fixes we need).
Zayooo00
force-pushed
the
feat/combobox-headlessui-v2-anchor
branch
from
August 31, 2026 10:49
f9d6bed to
ff18b03
Compare
Zayooo00
enabled auto-merge (squash)
August 31, 2026 10:56
dosmiko7
approved these changes
Aug 31, 2026
Zayooo00
added a commit
to myevaluations/myevals-plasmic-utils
that referenced
this pull request
Aug 31, 2026
…-3088) (fullstackhouse#62) (#4) Migrate the Combobox code component from Headless UI v1 to v2 so the dropdown menu is portalled and positioned by Floating UI instead of being an abspos child of the input. This lets the menu escape any `overflow` ancestor (it was previously clipped inside narrow containers, e.g. the Institutional Program Assessment sidebar) and flip/shift to stay in the viewport. - `Combobox.Input/Button/Options/Option` -> v2 named components; drop the `<Transition>` wrapper for the `transition` prop + `[data-closed]`; drop `nullable`; reset the query on `onClose`. - Replace the `arrowIconRef.click()` focus hack with `immediate` (kept a slim `onClick` so re-clicking a focused input reopens the menu). - New `menuWidth` prop: `"input"` (default, unchanged behaviour) or `"fit"` (grows to the widest option, never narrower than the input). `width`/`min-width` are applied inline so they win over a leftover `width` in `optionsClassName`; `max-width` is left to CSS so callers can still cap it. - Split the menu into `.positioner` (what Floating UI portals/positions and stamps an inline `max-width: <viewport>` onto) and an inner `.options` wrapper that carries all author-facing sizing/look, so a caller's `max-width` is no longer overridden. - `anchor` gap of 1px + restored top `clip-path` keep `"input"` mode visually identical to before. - Option-state selectors for `optionClassName` move from `[data-headlessui-state*=active]` etc. to v2's `[data-focus]` / `[data-selected]` / `[data-disabled]`. - Bump the `@headlessui/react` peer range to ^2.2.0 (2.2.x carries the Combobox open-on-trigger and `immediate` fixes we need).
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.
Problem
The
Comboboxdropdown menu renders as aposition: absolutechild of the input. In a narrow container it is clipped by anoverflowancestor and can render off-screen with no flip/shift — most visibly the department picker in the Institutional Program Assessment sidebar, where long option labels wrap across several lines and a caller-setmax-widthhas no effect.Change
Migrate the code component from Headless UI v1 → v2 and use
anchoronComboboxOptions, which portals the menu to<body>and positions it with Floating UI (flip + shift + viewport padding).Behaviour
menuWidthprop."input"(default) — the menu is exactly as wide as the input. Visually identical to today (anchorgap of1px+ restored topclip-path)."fit"— the menu grows to the widest option (long labels stop wrapping), never narrower than the input. Cap it withmax-widthonoptionsClassName.width/min-widthare set inline (they win over a leftoverwidthinoptionsClassName);max-widthis left to CSS so callers keep control of it..positioner(portalled + positioned by Floating UI, which stamps an inlinemax-width: <viewport>onto it every reposition) and an inner.optionswrapper that carries all author-facing sizing and styling — so a caller'smax-widthis no longer clobbered.immediatereplaces the oldarrowIconRef.click()focus hack; a slimonClickis kept so re-clicking an already-focused input reopens the menu.<Transition>wrapper →transitionprop +.positioner[data-closed](same 0.1s opacity fade).nullabledropped (v2 native). Query resets ononClose.<Combobox.Label>→<div role="presentation">(same class/text).Breaking
@headlessui/reactpeer range bumped to^2.2.0. 2.2.x carries the Combobox open-on-trigger andimmediatefixes; installed 2.1.8 had a regression where clicking the trailing button did not open the menu. The only consumer (myevals-plasmic-utils→myevals-react-frontend) has no other Headless UI usage; it bumps alongside.optionClassNamestate selectors move from[data-headlessui-state*=active]/[aria-selected=true]/[aria-disabled=true]to v2's[data-focus]/[data-selected]/[data-disabled]. The active / selected / highlighted / disabled option styles need re-verifying in Plasmic Studio after the registration re-syncs.Verified
tsc -p tsconfig.package.json,next lint,vitest(49 pass) green.yarn build+ link intomyevals-react-frontend:inputmode matches the current menu;fitmode grows to content and honours amax-widthset viaoptionsClassName; open-on-focus, filtering, empty state, 500-result cap, footer slot, grouped options all work.Follow-ups (not in this PR)
myevaluations/myevals-plasmic-utils(fork differs only by the org rename).@headlessui/reactinmyevals-react-frontend, re-sync Plasmic, re-style option states, add themenuWidth="fit"variant to the department picker.