ui icon indicating copy to clipboard operation
ui copied to clipboard

[bug]: Can't open DropdownMenu when using with AlertDialog together

Open zwelhtetyan opened this issue 1 year ago • 10 comments
trafficstars

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

zwelhtetyan avatar Sep 19 '24 07:09 zwelhtetyan

The codesandbox link is invalid I go in but there is no code for shadcn

joseph0926 avatar Sep 19 '24 08:09 joseph0926

same scenario, solved with <AlertDialog open={open} onOpenChange={setOpen}>

iamolegga avatar Sep 19 '24 20:09 iamolegga

same scenario, solved with <AlertDialog open={open} onOpenChange={setOpen}>

Not working for me

zwelhtetyan avatar Sep 20 '24 03:09 zwelhtetyan

In the modified code sandbox, the “dropdown-menu” seems to work normally after the “alert-dialog” is closed Is this not the problem?

joseph0926 avatar Sep 20 '24 03:09 joseph0926

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 avatar Sep 20 '24 03:09 zwelhtetyan

@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

anubhavadarsh avatar Sep 20 '24 06:09 anubhavadarsh

@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 avatar Sep 20 '24 14:09 zwelhtetyan

@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.

anubhavadarsh avatar Sep 20 '24 14:09 anubhavadarsh

<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.

Char99s avatar Sep 20 '24 19:09 Char99s

Fix the issues by updating @radix-ui/react-alert-dialog to version 1.1.2

npm install @radix-ui/react-alert-dialog@latest

KoenRijpstra avatar Oct 02 '24 10:10 KoenRijpstra

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.

image

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.

eriknyk avatar Oct 23 '24 15:10 eriknyk

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.

image 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.

davidfcopozo avatar Nov 19 '24 18:11 davidfcopozo

I've tried all the possible solutions listed (and even noted listed) here, be it with

  • controlled state
  • with e.preventDefault() and e.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.

samuelhulla avatar Dec 25 '24 13:12 samuelhulla

I've tried all the possible solutions listed (and even noted listed) here, be it with

  • controlled state
  • with e.preventDefault() and e.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.

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 avatar Jan 07 '25 20:01 alexevladgabriel

@alexevladgabriel bro, your mutation observer saved me a day, thank you!

OlegBabakov avatar Feb 04 '25 19:02 OlegBabakov

@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.

18-28 avatar Mar 08 '25 22:03 18-28

When persist error in:

  1. "@radix-ui/react-dropdown-menu": "^2.1.12",
  2. "@radix-ui/react-alert-dialog": "^1.1.14",

the answer given here, solves it. However, if using shadcn, just point the dependency to:

  1. /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)
        }}
      />
    </>
  )
}

MateusNGF avatar Jun 26 '25 14:06 MateusNGF

Setting <DropdownMenu modal={false}> solved the issue, but i do not know the reason

NibrasoftNet avatar Jul 29 '25 13:07 NibrasoftNet

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.

Jhvcc avatar Aug 25 '25 07:08 Jhvcc

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

shadcn avatar Oct 16 '25 10:10 shadcn