diff --git a/src/code-components/Combobox/Combobox.module.css b/src/code-components/Combobox/Combobox.module.css index 151456ab..ff72ce50 100644 --- a/src/code-components/Combobox/Combobox.module.css +++ b/src/code-components/Combobox/Combobox.module.css @@ -36,6 +36,14 @@ .positioner { transition: opacity 0.1s ease-in; overflow: visible !important; + /* + * The menu is portalled to `document.body`. A Radix modal dialog sets + * `pointer-events: none` on `body` while open and restores `auto` only on its + * own content element, so a menu opened from inside a dialog would render but + * ignore every click. `pointer-events` inherits, so re-enabling it here covers + * the whole menu subtree. Harmless outside a dialog. + */ + pointer-events: auto; } .positioner[data-closed] { diff --git a/src/code-components/DialogV2/DialogV2.tsx b/src/code-components/DialogV2/DialogV2.tsx index c1aa3ba2..555ad598 100644 --- a/src/code-components/DialogV2/DialogV2.tsx +++ b/src/code-components/DialogV2/DialogV2.tsx @@ -62,6 +62,10 @@ export function DialogV2({ event.preventDefault(); }} onPointerDownOutside={(event) => { + if (isHeadlessUiPortalClick(event)) { + event.preventDefault(); + return; + } preventEventIfScrollbarClick(event); onPointerDownOutside?.(event); }} @@ -74,6 +78,19 @@ export function DialogV2({ ); } +/** + * A Headless UI menu (Combobox, Listbox, Menu) opened from inside the dialog is + * portalled to `document.body`, so Radix sees a click on one of its options as a + * click outside the dialog and closes it mid-selection. Treat those clicks as + * inside. + */ +function isHeadlessUiPortalClick(event: PointerDownOutsideEvent) { + const target = event.target; + return ( + target instanceof Element && !!target.closest("[data-headlessui-portal]") + ); +} + /** * Based on https://github.com/tailwindlabs/headlessui/pull/1333/files#diff-d095a5f3fa3ad7f5ff99576cb61e5d75a979a6b7d5557f8a092f5d5c8c0c34deR49 */