Issue:
If there is a DropdownMenu component inside the Dialogue, and both the Dialogue and DropdownMenu are opened, then on clicking outside the Dialogue or closing the Dialogue will cause the whole app to freeze and cannot interact further.
Reason:
When the Dialogue is closed, the DropdownMenu didn't get the chance to close, thus even though the Dialogue and DropdownMenu are unmounted the state of DropdowndMenu hasn't changed, causing the app to inert/ Unclickable.
Solution:
If any dropdown menu content is currently mounted, prevent the dialog from closing.
This avoids a race where the dialog closes first and leaves the page inert/unclickable because the dropdown didn't get a chance to close itself.Add a check to prevent the Dialogue from closing if there is dropdownMenu mounted
<DialogContent
onInteractOutside={(event) => {
// Prevent closing the dialog if a dropdown is currently open.
// This check works with your DropdownMenu wrapper because it sets data-slot attributes.
const hasOpenDropdown =
document.querySelector('[data-slot="dropdown-menu-content"]') !== null ||
document.querySelector('[data-slot="dropdown-menu-sub-content"]') !== null;
if (hasOpenDropdown) {
event.preventDefault();
}
}}
>
Full code
import * as React from "react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
// If you use your local wrapper from `components/ui/dropdown-menu`
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
} from "@/components/ui/dropdown-menu";
export function DialogWithDropdownExample() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent
onInteractOutside={(event) => {
// Prevent closing the dialog if a dropdown is currently open.
// This check works with your DropdownMenu wrapper because it sets data-slot attributes.
const hasOpenDropdown =
document.querySelector('[data-slot="dropdown-menu-content"]') !== null ||
document.querySelector('[data-slot="dropdown-menu-sub-content"]') !== null;
if (hasOpenDropdown) {
event.preventDefault();
}
}}
>
<DialogHeader>
<DialogTitle>Dialog with Dropdown</DialogTitle>
</DialogHeader>
<div className="flex items-center gap-3">
<span>Choose an option:</span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open dropdown</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onSelect={(e) => e.preventDefault()}>
Action 1
</DropdownMenuItem>
<DropdownMenuItem onSelect={(e) => e.preventDefault()}>
Action 2
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</DialogContent>
</Dialog>
);
}
Top comments (0)