fix(Combobox): make the portalled menu clickable inside a modal dialog (MET-3088) - #66
Merged
Merged
Conversation
…g (MET-3088) Since the menu moved to a Headless UI portal it renders under `document.body`, outside the dialog. Radix's modal `Dialog` sets `pointer-events: none` on `body` while open and restores `auto` only on its own content element, so the menu inherited `none`: it opened and rendered, but every click passed through to the dialog behind it. Keyboard selection still worked, which is what gave it away. Re-enable pointer events on `.positioner`, the portalled root, so the whole menu subtree is hit-testable again. That alone lets the click reach Radix, which reads a pointerdown on the menu as an interaction outside the dialog and closes it mid-selection. So `DialogV2` now treats a pointerdown inside a Headless UI portal as inside the dialog and prevents the dismissal. Affects every dialog that hosts a Combobox — 13 components in the app.
patrykbojczuk
approved these changes
Sep 8, 2026
Zayooo00
added a commit
to myevaluations/myevals-plasmic-utils
that referenced
this pull request
Sep 8, 2026
…g (MET-3088) (fullstackhouse#66) (#9) Since the menu moved to a Headless UI portal it renders under `document.body`, outside the dialog. Radix's modal `Dialog` sets `pointer-events: none` on `body` while open and restores `auto` only on its own content element, so the menu inherited `none`: it opened and rendered, but every click passed through to the dialog behind it. Keyboard selection still worked, which is what gave it away. Re-enable pointer events on `.positioner`, the portalled root, so the whole menu subtree is hit-testable again. That alone lets the click reach Radix, which reads a pointerdown on the menu as an interaction outside the dialog and closes it mid-selection. So `DialogV2` now treats a pointerdown inside a Headless UI portal as inside the dialog and prevents the dismissal. Affects every dialog that hosts a Combobox — 13 components in the app.
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
A Combobox opened from inside a
DialogV2modal renders its dropdown, but no option can be clicked. Keyboard selection (arrows + Enter) works, which is the tell: the DOM is fine, the pointer never reaches the options.Regression from #62, where the menu moved to a Headless UI portal.
Cause
With
anchor, Headless UI portalsComboboxOptionsinto<div data-headlessui-portal>underdocument.body— outsideDialog.Content.Radix's modal
DialogpassesdisableOutsidePointerEvents: true, andDismissableLayerresponds by settingdocument.body.style.pointerEvents = "none", restoringautoonly on the layer node (the dialog content).pointer-eventsinherits, so the portalled menu computed tonone— it painted normally and ignored every click, which landed on the dialog behind it.Measured in the app with the menu open:
Fix
pointer-events: autoon.positioner, the portalled root. A descendant withautois hit-testable even when an ancestor isnone, so this covers the whole menu subtree and is a no-op outside a dialog.That alone makes the click reach Radix, which sees a pointerdown outside
Dialog.Contentand dismisses the dialog mid-selection. SoDialogV2now treats a pointerdown inside[data-headlessui-portal]as inside the dialog and callspreventDefault()— the same lever the existing scrollbar guard uses, since Radix composes the caller's handler ahead of its own and skips dismissal when the event is default-prevented.Both parts are needed; either alone leaves the interaction broken.
Scope
13 components in the consuming app pair a dialog with a Combobox — settings modals, print modals, breakdown modals, details dialogs. All have had unclickable dropdowns since #62.
Verification
npm run build,npx vitest run(8 files, 49 tests),npm run lint— all passnode_modulesand exercised against a local dev build: options select by mouse, and picking one no longer closes the dialogaria-hidden@1.2.4is imported ashideOthers, notinertOthers, so nothing isinertand that path was not a factor