primitives icon indicating copy to clipboard operation
primitives copied to clipboard

Opening a Dialog programmatically from a Dropdown Menu item freezes the UI

Open gdehmlow opened this issue 11 months ago • 16 comments

Bug report

Current Behavior

This is very specific, but I want to open a Dialog programmatically by clicking on a Dropdown menu item.

ezgif-5-1f6599d0f4

Basically, body gets stuck with pointer-events: none after closing the modal.

Expected behavior

After closing the modal, body should not have pointer-events: none set.

Reproducible example

[https://codesandbox.io/p/devbox/condescending-thunder-fdtprf](Codesandbox Repro)

Suggested solution

My solution was delaying the opening of the modal to the next cycle via setTimeout(() => { setOpen(true); }, 0);, but this feels kind of kludgy.

The issue probably has to do with two conflicting underlying DismissableLayers messing with each other, esp. with regards to originalBodyPointerEvents. My guess is that when Dialog mounts, because of DropdownMenu not having its cleanup effect run, body still has pointer-events: none set, so that's what Dialog thinks is the proper originalBodyPointerEvents. When the Dialog unmounts.. it "resets" to that value - pointer-events: none.

I know this is an edge case, and I'm not sure if there is actually a robust solution to this besides just manually handling it the way I did (besides having some sort of system to maintain a "stack" of pointer-event values, which would probably require wrapping the components in a wrapper context... bleh).

But I thought I would just throw this out there in case someone has a better idea.

gdehmlow avatar Jan 10 '25 03:01 gdehmlow

When you are using components that uses an overlay such as dropdown or dialog. You need to keep there versions in sync. They apparently end up using different versions of a the browser api. That causes some conflicts.

Make sure to sync the versions of dialog and dropdown that you have to x.x.4

FredrikMWold avatar Jan 12 '25 22:01 FredrikMWold

I was trying to open a sheet in a select in shadcn/ui - they are components made with select and dialog in radix-ui and I had exactly the same problem.

I followed @FredrikMWold's solution to make everything in radix-ui up to date and it works!

kmelon55 avatar Jan 14 '25 04:01 kmelon55

We have the same problem. We use latest versions of both packages, that at the moment are:

  • @radix-ui/react-dropdown-menu 2.1.4
  • @radix-ui/react-dialog 1.1.4

We still can reproduce the issue. As temp workaround we postponed the moment the dialog gets opened (so that it doesn't save pointer-events: none as original value)… but it would be nice to not have to do that.

brunouber avatar Jan 22 '25 14:01 brunouber

Just adding a datapoint here. I have multiple projects in which this has happened. In some, upgrading & aligning versions of @radix-ui/* packages worked. In others, I had to resort to using workarounds such as clearing style.pointerEvents = "" when .e.g clicking a link in a Sidebar. It seems like this happens every time a sidebar (or other overlay, such as that of a modal) is opened and then not closed before a link is clicked and causes the browser to navigate to a new route. The pointer events "none" stay applied in this case.

rszalski avatar Feb 12 '25 18:02 rszalski

Experiencing the same with latest radix-ui components. (I'm only using dropdown menu and scroll area anyway. Also seeing pointer events none applied permanently.

etodanik avatar Feb 24 '25 13:02 etodanik

If just updating did not help. Then I recommend deleting node_modules and reinstalling. I have had problems with upgrading radix before especially scroll area.

FredrikMWold avatar Feb 24 '25 13:02 FredrikMWold

Have the same issue with the DropdownMenu:

  • @radix-ui/react-dropdown-menu/^2.1.6

had to remove pointer-events to get the content to be interactive after triggering the menu:

      <DropdownMenu
        open={open}
        onOpenChange={(isOpen) => {
          setOpen(isOpen);
          if (!isOpen) {
            document.body.style.removeProperty('pointer-events');
          }
        }}
      >

karimbeyrouti avatar Mar 10 '25 21:03 karimbeyrouti

This very same problem resurfaced again for us - this time we fixed by defining an override for "@radix-ui/react-dismissable-layer".

brunouber avatar Apr 24 '25 10:04 brunouber

https://github.com/radix-ui/primitives/issues/3495

flex-hyuntae avatar Apr 29 '25 01:04 flex-hyuntae

This very same problem resurfaced again for us - this time we fixed by defining an override for "@radix-ui/react-dismissable-layer".

Which version did you pin it to?

this is wildly frustrating 😂

Aleksion avatar Jul 17 '25 01:07 Aleksion

@Aleksion

"overrides": {
        "@radix-ui/react-dismissable-layer": "1.1.7",
        "@radix-ui/react-slot": "1.2.0"
    }

brunouber avatar Jul 17 '25 05:07 brunouber

If you're using Vite and are seeing this issue even after updating to the latest component versions, ensure that both @radix-ui/react-dialog and @radix-ui/react-dropdown-menu are not being optimised. It can lead to the components each using a different version of @radix-ui/react-dismissable-layer as their dependencies get bundled separately.

i.e. in your Vite config:

optimizeDeps: {
  exclude: [
    '@radix-ui/react-dialog',
    '@radix-ui/react-dropdown-menu',

    // It's worth including other components that share @radix-ui/react-dismissable-layer if you use those also...
    '@radix-ui/react-popover',
    '@radix-ui/react-select',
  ],
},

dsrominiyi avatar Jul 21 '25 16:07 dsrominiyi

I believe this is indeed caused by multiple instances of DismissableLayer running at the same time. I managed to resolve this in my project by first making sure every package used the same version of @radix-ui/react-dismissable-layer, and then deduplicating that dependency.

Starting point:

$ npm explain @radix-ui/react-dismissable-layer
@radix-ui/[email protected]
node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer
  @radix-ui/react-dismissable-layer@"1.1.11" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-dialog
    @radix-ui/react-dialog@"^1.1.15" from the root project

@radix-ui/[email protected]
node_modules/@radix-ui/react-dismissable-layer
  @radix-ui/react-dismissable-layer@"1.1.10" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog
    @radix-ui/react-dialog@"1.1.14" from @radix-ui/[email protected]
    node_modules/@radix-ui/react-alert-dialog
      @radix-ui/react-alert-dialog@"^1.1.14" from the root project

@radix-ui/[email protected]
node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer
  @radix-ui/react-dismissable-layer@"1.1.11" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-menu
    @radix-ui/react-menu@"2.1.16" from @radix-ui/[email protected]
    node_modules/@radix-ui/react-dropdown-menu
      @radix-ui/react-dropdown-menu@"^2.1.16" from the root project

@radix-ui/[email protected]
node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer
  @radix-ui/react-dismissable-layer@"1.1.11" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-select

Update the dragging package and deduplicate dismissable layer:

$ npm install @radix-ui/react-alert-dialog
$ npm dedupe
$ npm explain @radix-ui/react-dismissable-layer
@radix-ui/[email protected]
node_modules/@radix-ui/react-dismissable-layer
  @radix-ui/react-dismissable-layer@"1.1.11" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-dialog
    @radix-ui/react-dialog@"^1.1.15" from the root project
    @radix-ui/react-dialog@"1.1.15" from @radix-ui/[email protected]
    node_modules/@radix-ui/react-alert-dialog
      @radix-ui/react-alert-dialog@"^1.1.15" from the root project
  @radix-ui/react-dismissable-layer@"1.1.11" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-menu
    @radix-ui/react-menu@"2.1.16" from @radix-ui/[email protected]
    node_modules/@radix-ui/react-dropdown-menu
      @radix-ui/react-dropdown-menu@"^2.1.16" from the root project
  @radix-ui/react-dismissable-layer@"1.1.11" from @radix-ui/[email protected]
  node_modules/@radix-ui/react-select
    @radix-ui/react-select@"^2.2.6" from the root project

markuslewin avatar Sep 04 '25 17:09 markuslewin

I ran into this problem and ended up solving it in a similar way to the last comment ☝️

I ran npm explain @radix-ui/react-dismissable-layer and then updated all the packages using it to their latest versions, which resolved my issues. These were the specific updates that were made in my project:

"@radix-ui/react-alert-dialog": "^1.1.13" -> "@radix-ui/react-alert-dialog": "^1.1.15"
"@radix-ui/react-dialog": "^1.1.13" -> "@radix-ui/react-dialog": "^1.1.15"
"@radix-ui/react-popover": "^1.1.6" -> "@radix-ui/react-popover": "^1.1.15"
"@radix-ui/react-tooltip": "^1.1.8" -> "@radix-ui/react-tooltip": "^1.2.8"

lpatino10 avatar Oct 02 '25 16:10 lpatino10

I faced similar issue. For me, the issue occurred when I opening select content on dialog and clicking modal overlay. After some digging, I could find a https://github.com/radix-ui/primitives/issues/3445#issuecomment-2795723995 posted on similar issue that he just updated package and it worked.

So I searched release note of radix ui and I could find that there are several updates to address similar issues like this.

Image

So I updated versions of radix ui packages(dialog, select) and "pointer-events: none" is no more leaving from that moment.

@radix-ui/react-dialog: 1.1.14 -> 1.1.15
@radix-ui/react-select: 1.2.2 -> 2.2.6

eunsukimme avatar Oct 28 '25 14:10 eunsukimme

Experiencing the same problem with

@radix-ui/[email protected]
@radix-ui/[email protected]

Solved by

@radix-ui/[email protected] ->1.1.15
@radix-ui/[email protected] -> 2.1.16 (same)
@radix-ui/[email protected] -> 1.1.15
@radix-ui/[email protected] -> 1.1.15

iord-eduardgabriel avatar Oct 31 '25 08:10 iord-eduardgabriel