diff --git a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx index a69e75b8b6..6d6ae09bcc 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.test.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.test.tsx @@ -806,6 +806,43 @@ describe('Mouse interactions', () => { expect(wrapperFn).toHaveBeenCalledTimes(0) }) ) + + it( + 'should should be possible to click on removed elements without closing the Dialog', + suppressConsoleLogs(async () => { + function Example() { + let [isOpen, setIsOpen] = useState(true) + let wrapper = useRef(null) + + return ( + +
+ Contents + + +
+
+ ) + } + render() + + // Verify it is open + assertDialog({ state: DialogState.Visible }) + + // Click the button inside the the Dialog + await click(getByText('Inside')) + + // Verify it is still open + assertDialog({ state: DialogState.Visible }) + }) + ) }) describe('Nesting', () => { diff --git a/packages/@headlessui-react/src/hooks/use-outside-click.ts b/packages/@headlessui-react/src/hooks/use-outside-click.ts index ccc0a0e311..8e9c2ac940 100644 --- a/packages/@headlessui-react/src/hooks/use-outside-click.ts +++ b/packages/@headlessui-react/src/hooks/use-outside-click.ts @@ -47,6 +47,10 @@ export function useOutsideClick( let target = event.target as HTMLElement + // Ignore if the target doesn't exist in the DOM anymore + if (!target.ownerDocument.documentElement.contains(target)) return + + // Ignore if the target exists in one of the containers for (let container of _containers) { if (container === null) continue let domNode = container instanceof HTMLElement ? container : container.current diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts index 3aee469583..ee25da3a64 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.test.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.test.ts @@ -997,6 +997,44 @@ describe('Mouse interactions', () => { expect(wrapperFn).toHaveBeenCalledTimes(0) }) ) + + it( + 'should should be possible to click on removed elements without closing the Dialog', + suppressConsoleLogs(async () => { + renderTemplate({ + template: ` + +
+ Contents + + + +
+
+ `, + setup() { + let isOpen = ref(true) + let wrapper = ref(null) + return { + isOpen, + wrapper, + setIsOpen(value: boolean) { + isOpen.value = value + }, + } + }, + }) + + // Verify it is open + assertDialog({ state: DialogState.Visible }) + + // Click the button inside the the Dialog + await click(getByText('Inside')) + + // Verify it is still open + assertDialog({ state: DialogState.Visible }) + }) + ) }) describe('Nesting', () => { diff --git a/packages/@headlessui-vue/src/hooks/use-outside-click.ts b/packages/@headlessui-vue/src/hooks/use-outside-click.ts index f0982d4e13..8b4aabc7fd 100644 --- a/packages/@headlessui-vue/src/hooks/use-outside-click.ts +++ b/packages/@headlessui-vue/src/hooks/use-outside-click.ts @@ -34,6 +34,10 @@ export function useOutsideClick( }) let target = event.target as HTMLElement + + // Ignore if the target doesn't exist in the DOM anymore + if (!target.ownerDocument.documentElement.contains(target)) return + let _containers = (() => { if (Array.isArray(containers)) { return containers @@ -46,6 +50,7 @@ export function useOutsideClick( return [containers] })() + // Ignore if the target exists in one of the containers for (let container of _containers) { if (container === null) continue let domNode = container instanceof HTMLElement ? container : dom(container)