ui
ui copied to clipboard
[bug]: Can't open DropdownMenu when using with AlertDialog together
Describe the bug
export default function Test() {
const [open, setOpen] = useState(false);
return (
<div className="p-20">
<DropdownMenu>
<DropdownMenuTrigger>Open</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem>
<Button onClick={() => setOpen(true)}>open dialog</Button> // open dialog
</DropdownMenuContent>
</DropdownMenu>
<AlertDialog open={open}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={() => setOpen(false)}> // close dialog
Cancel
</AlertDialogCancel>
<AlertDialogAction>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
);
}
Can't open DropdownMenu again after closing AlertDialog
Affected component/components
DropdownMenu, AlertDialog
How to reproduce
Codesandbox/StackBlitz link
https://codesandbox.io/p/sandbox/shadcnui-issue-44hxn3
Logs
No response
System Info
---
Before submitting
- [X] I've made research efforts and searched the documentation
- [X] I've searched for existing issues
The codesandbox link is invalid I go in but there is no code for shadcn
same scenario, solved with <AlertDialog open={open} onOpenChange={setOpen}>
same scenario, solved with
<AlertDialog open={open} onOpenChange={setOpen}>
Not working for me
In the modified code sandbox, the “dropdown-menu” seems to work normally after the “alert-dialog” is closed Is this not the problem?
In the modified code sandbox, the “dropdown-menu” seems to work normally after the “alert-dialog” is closed Is this not the problem?
I found it a bit tricky to add tailwind and shadcn config in sandbox. So this is not the complete version. It is not working with overlay styling in the original version.
@zwelhtetyan , I tried reproducing the said issue in my local build. I am able to open "dropdown-menu", after the "alert-dialog" has been closed. I have attached a video for the said behavior as well. https://github.com/user-attachments/assets/06f7e5d8-1e51-4c9d-9d21-76abfc9bc673
@zwelhtetyan , I tried reproducing the said issue in my local build. I am able to open "dropdown-menu", after the "alert-dialog" has been closed. I have attached a video for the said behavior as well. https://github.com/user-attachments/assets/06f7e5d8-1e51-4c9d-9d21-76abfc9bc673
How you handle opening alert dialog? State or trigger button?
@zwelhtetyan , I tried reproducing the said issue in my local build. I am able to open "dropdown-menu", after the "alert-dialog" has been closed. I have attached a video for the said behavior as well. https://github.com/user-attachments/assets/06f7e5d8-1e51-4c9d-9d21-76abfc9bc673
How you handle opening alert dialog? State or trigger button?
I used states, it was the same code you shared with the bug description.
<AlertDialogCancel onClick={(e) => {e.preventDefault(); setOpen(false)}}>
Try using e.preventDefault() as shown above because I encountered the same error and the dropdown menu was initially closing with the dialog since you clicked outside of it.
Fix the issues by updating @radix-ui/react-alert-dialog to version 1.1.2
npm install @radix-ui/react-alert-dialog@latest
I've faced the same issue in a recent app, I recently added the alert-dialog component, it's already using the v1.1.2 of @radix-ui/react-alert-dialog and the problem still occurs.
I've noticed that when the dialog is closed it is adding a style="pointer-events: none;" property to thml body tag and it's blocking the pointer event on the entire page.
I'm pretty sure that it's being added after close the dialog because I've monitored on devtools elements tab, and if you remove that style prop manually (from devtools elements tab) the page backs to normal.
I've faced the same issue in a recent app, I recently added the alert-dialog component, it's already using the
v1.1.2of@radix-ui/react-alert-dialogand the problem still occurs. I've noticed that when the dialog is closed it is adding astyle="pointer-events: none;"property to thml body tag and it's blocking the pointer event on the entire page.I'm pretty sure that it's being added after close the dialog because I've monitored on devtools elements tab, and if you remove that style prop manually (from devtools elements tab) the page backs to normal.
I'm having the same issue, the only workaround I could think about is to set the pointer-events to auto with the !important modifier, I'm sure is not the best solution, but if anybody has a more optimum solution, please let me know.
I've tried all the possible solutions listed (and even noted listed) here, be it with
- controlled state
- with
e.preventDefault()ande.stopPropagation() - overriding
document.body.style.pointerEvents - and even shuffling around the dialog / dropdownmenu structure
<Dialog>
<DropdownMenu>
{/* ... */}
<DropdownMenuItem>
<DialogTrigger>open</DialogTrigger>
</DropdownMenuItem>
{/* .... */}
</DropdownMenu>
<DialogContent>
...
</DialogContent>
</Dialog>
and
<DropdownMenu>
{/* ... */}
<DropdownMenuItem>
<Dialog>
<DialogTrigger>open</DialogTrigger>
<DialogContent>...</DialogContent>
</Dialog>
</DropdownMenuItem>
{/* ... */}
</DropdownMenu>
But none of the solutions work.
The only way I truly got it to work was by programatically reloading the page, i.e.
const onSubmit: MouseEventHandler<HTMLButtonElement> = async (e) => {
try {
// ...
} catch (err) {
// ...
} finally {
document.location.reload()
}
}
This overrides the stuck pointer-events which was blocing the dialogs. Silly, but as far as I know this is the only solution that truly works everywhere.
I've tried all the possible solutions listed (and even noted listed) here, be it with
- controlled state
- with
e.preventDefault()ande.stopPropagation()- overriding
document.body.style.pointerEvents- and even shuffling around the dialog / dropdownmenu structure
<Dialog> <DropdownMenu> {/* ... */} <DropdownMenuItem> <DialogTrigger>open</DialogTrigger> </DropdownMenuItem> {/* .... */} </DropdownMenu> <DialogContent> ... </DialogContent> </Dialog>and
<DropdownMenu> {/* ... */} <DropdownMenuItem> <Dialog> <DialogTrigger>open</DialogTrigger> <DialogContent>...</DialogContent> </Dialog> </DropdownMenuItem> {/* ... */} </DropdownMenu>But none of the solutions work.
The only way I truly got it to work was by programatically reloading the page, i.e.
const onSubmit: MouseEventHandler<HTMLButtonElement> = async (e) => { try { // ... } catch (err) { // ... } finally { document.location.reload() } }This overrides the stuck
pointer-eventswhich was blocing the dialogs. Silly, but as far as I know this is the only solution that truly works everywhere.
This should work fine for you, at least it works for me. I have the same situation as you.
useEffect(() => {
// Callback to handle DOM changes
const handleDomChanges = (mutationsList: MutationRecord[]) => {
for (const mutation of mutationsList) {
if (
mutation.type === "attributes" &&
mutation.attributeName === "style"
) {
const pointerEvents = document.body.style.pointerEvents;
console.log("Pointer Events changed:", pointerEvents);
// Reset pointer-events if set to 'none'
if (pointerEvents === "none") {
document.body.style.pointerEvents = "";
console.log("Pointer Events reset to default");
}
}
}
};
// Create a MutationObserver instance
const observer = new MutationObserver(handleDomChanges);
// Start observing the body element for style attribute changes
observer.observe(document.body, {
attributes: true, // Watch for attribute changes
attributeFilter: ["style"], // Only observe changes to 'style'
});
// Cleanup the observer when the component unmounts
return () => observer.disconnect();
}, []); // Empty dependency array ensures it runs once
@alexevladgabriel bro, your mutation observer saved me a day, thank you!
@alexevladgabriel this fixed worked for me, thanks for sharing.
horrible to have to add all that extra code though, hopefully the bug gets resolved at some point.
When persist error in:
- "@radix-ui/react-dropdown-menu": "^2.1.12",
- "@radix-ui/react-alert-dialog": "^1.1.14",
the answer given here, solves it. However, if using shadcn, just point the dependency to:
- /ui/alert-dialog -> shadcn
export interface ContentModal {
title: string,
description: string
onConfirm: () => void
}
interface IDialogConfirmantionProps {
params?: ContentModal
open: boolean
onClose: (bol: boolean) => void
}
export function DialogConfirmantion({ params, open, onClose }: IDialogConfirmantionProps) {
if (!params) {
return (<></>)
}
return (
<AlertDialog open={open} onOpenChange={onClose} >
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{params.title}</AlertDialogTitle>
<AlertDialogDescription>
{params.description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancelar</AlertDialogCancel>
<AlertDialogAction onClick={params.onConfirm}>Confirmar</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}
export function ClientRowActions({
row,
}: DataTableRowActionsProps) {
const client = row.original
const [openDialogConfirmantion, setOpenDialogConfirmantion] = React.useState(false)
const [contentDialogConfirmantion, setContentDialogConfirmantion] = React.useState<ContentModal | undefined>(undefined)
const PARAMETERS: IParameters = {
"archive": {
title: "Arquivar",
description: " Ao arquivar esse consumidor, ele não será mais exibido nas listagem, no entanto, ainda podem aparecer em transações, documentos efetivados anteriormente.",
onConfirm: () => { window.alert("Arquivado") }
},
"edit": {
title: "Editar",
description: "Ao editar esse consumidor, ele será exibido nas listagem, no entanto, ainda podem aparecer em transações, documentos efetivados anteriormente.",
onConfirm: () => { }
}
}
function triggerDialog(action: string) {
const content = PARAMETERS[action]
setContentDialogConfirmantion(content)
setOpenDialogConfirmantion(true)
}
return (
<>
<DropdownMenu modal={true}>
<DropdownMenuTrigger asChild>
<Button
variant='ghost'
className='data-[state=open]:bg-muted flex h-8 w-8 p-0'
>
<IconDotsCircleHorizontal className='h-4 w-4' />
<span className='sr-only'>Menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='start' className='w-[160px]'>
<DropdownMenuItem
variant='destructive'
onClick={() => triggerDialog("archive")}
>
Arquivar
<DropdownMenuShortcut>
<ArchiveIcon color='red' size={16} />
</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<DialogConfirmantion
params={contentDialogConfirmantion}
open={openDialogConfirmantion}
onClose={e => {
setOpenDialogConfirmantion(e)
setContentDialogConfirmantion(undefined)
}}
/>
</>
)
}
Setting <DropdownMenu modal={false}> solved the issue, but i do not know the reason
Describe the bug
export default function Test() { const [open, setOpen] = useState(false);
return ( <div className="p-20"> <DropdownMenu> <DropdownMenuTrigger>Open</DropdownMenuTrigger> <DropdownMenuContent> <DropdownMenuLabel>My Account</DropdownMenuLabel> <DropdownMenuSeparator /> <DropdownMenuItem>Profile</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuItem>Team</DropdownMenuItem> <DropdownMenuItem>Subscription</DropdownMenuItem> <Button onClick={() => setOpen(true)}>open dialog</Button> // open dialog </DropdownMenuContent> </DropdownMenu>
<AlertDialog open={open}> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle> <AlertDialogDescription> This action cannot be undone. This will permanently delete your account and remove your data from our servers. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel onClick={() => setOpen(false)}> // close dialog Cancel </AlertDialogCancel> <AlertDialogAction>Continue</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> </div>); } Can't open DropdownMenu again after closing AlertDialog关闭 AlertDialog 后无法再次打开 DropdownMenu
Affected component/components
DropdownMenu, AlertDialog下拉菜单、警报对话框
How to reproduce
Codesandbox/StackBlitz link
https://codesandbox.io/p/sandbox/shadcnui-issue-44hxn3
Logs
No response 没有回应
System Info
Before submitting
- [x] I've made research efforts and searched the documentation我做了研究并搜索了文档[x] I've searched for existing issues我搜索过现有问题
I found the solution in #468, you can use modal={fasle} to solve it.
Hi. We're closing some old issues as outdated. If this is still relevant (and not fixed in main), leave a message, we'll reopen it. Thank you. Appreciate your contribution to the project - shadcn
I'm pretty sure that it's being added after close the dialog because I've monitored on devtools elements tab, and if you remove that style prop manually (from devtools elements tab) the page backs to normal.