mui / material-ui

Material UI: Ready-to-use foundational React components, free forever. It includes Material UI, which implements Google's Material Design.
https://mui.com/material-ui/
MIT License
92.43k stars 31.84k forks source link

[Backdrop] Stuck open at 0% opacity and blocks all clicks on the page due to react-transition-group bug #32286

Open joshribakoff-sm opened 2 years ago

joshribakoff-sm commented 2 years ago

Duplicates

Latest version

Current behavior 😯

backdrop should always unmount when animation is done

Expected behavior 🤔

backdrop gets stuck open, blocks interaction with page

Steps to reproduce 🕹

Honestly it is hard to replicate. Turn on strict mode and interact with the Menu rapidly, or hack the code to unmount & re-mount with the "existing" state when onExit fires but before onExited

Context 🔦

Please see this issue where I have done detailed work to isolate and write up what the issue is. https://github.com/reactjs/react-transition-group/issues/817

As shown here it gets stuck with in={false} and EXITING, it does not ever goto EXITED and unmount, from my user's perspective the whole app is crashed/frozen and they need to reload the page now. Screen Shot 2022-04-13 at 11 55 48 AM

This is because onExited fails to fire, due to race conditions, and it never hits here https://github.com/mui/material-ui/blob/master/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js#L202-L204

Your environment 🌎

Chrome, but it's irrelevant based on what I understand about this bug

`npx @mui/envinfo` ``` System: OS: macOS 11.6.4 Binaries: Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node Yarn: 1.22.17 - ~/.nvm/versions/node/v16.14.0/bin/yarn npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm Browsers: Chrome: 100.0.4896.88 Edge: Not Found Firefox: Not Found Safari: 15.4 npmPackages: @emotion/react: ^11.7.1 => 11.8.1 @emotion/styled: ^11.6.0 => 11.8.1 @mui/base: 5.0.0-alpha.70 @mui/icons-material: ^5.3.1 => 5.4.4 @mui/lab: ^5.0.0-alpha.66 => 5.0.0-alpha.71 @mui/material: ^5.3.1 => 5.4.4 @mui/private-theming: 5.4.4 @mui/styled-engine: 5.4.4 @mui/system: ^5.4.0 => 5.4.4 @mui/types: ^7.1.0 => 7.1.2 @mui/utils: ^5.3.0 => 5.4.4 @types/react: 17.0.30 => 17.0.30 react: ^18.0.0 => 18.0.0 react-dom: ^18.0.0 => 18.0.0 styled-components: 5.3.3 => 5.3.3 typescript: ~4.4.3 => 4.4.4 ```
mnajdova commented 2 years ago

Thanks for creating the issue and linking it to the react transition group's issue. Let's keep an eye on it to see if the maintainers will provide some feedback. I see that there is another issue opened related to React 18 there too.

doflo-dfa commented 1 year ago

This is a very hacky solution but ... it does solve the issues caused by this on modern browsers which should solve for 90% of our applications users ... I would not normally promote such a solution but without it the bug is a complete show stopper

div:has(div[style*="opacity: 0"]) {
  pointer-events: none;
}

or

div.MuiModal-root:has(> div[style*="opacity: 0"]) {
  pointer-events: none;
}
joacub commented 1 year ago

any updates in this ?

yukiyokotani commented 1 year ago

I have faced a similar problem. My application uses Next.js v12 and MUI v5, and the user makes screen transitions from the menu in the Drawer. In this situation, on rare occasions, the backdrop drawn by the MUI Drawer remains transparent on the screen, making the application inoperable. When the Drawer is working correctly, the Backdrop style is given visibility: hiddeen when the Drawer is closed, but when the above problem occurs, the Backdrop is not given visibility: hidden even though the Drawer is closed.

I debugged with React Developer Tools and confirmed that the state that the React Transition Group Transition is using internally is stuck at "exiting". I also checked the MUI source code and understood that the visibility: hidden is not given due to the following code control.

https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Slide/Slide.js#L255

We do not have a procedure to reproduce this problem, as it requires a certain scale and occurs stochastically.

gijsbotje commented 1 year ago

We have encountered the same problem with sites of two of our clients. Both are running on next 13 and using MUI 5. For us, it also happens when a route transition is triggered while a backdrop is visible. This happens while a dialog is open or our menu is open on which we add a backdrop.

I'm glad someone found the root of the problem, as it was impossible for us to recreate the bug consistently. Most of the time it will unmount as it should, but sometimes it gets stuck. Hope someone finds a fix for it soon.

gijsbotje commented 1 year ago

I implemented the hack @doflo-dfa mentioned in our theme config, so it only applies for the backdrop. This works fine for until the issue gets fixed.

const theme = createTheme({
  // ...
  components: {
    MuiBackdrop: {
      styleOverrides: {
        root: {
          '&[style*="opacity: 0"]': {
            pointerEvents: 'none',
          },
        },
      },
    },
  },
});

I've also found a way to reproduce this bug in a specific instance. If I open https://nextjs-azalp-9294f0bzd-azalp-de.vercel.app/ in browserstack with edge 112, it gets stuck when I double-click on a sub menu item. The open state of the backdrop is controlled by a state that gets set to false on click. Only the main menu items in the blue bar have the ability to change it to true on mouse over. Can't imagine a setState setting it to false running twice could trigger this. Thats also not the only time this bug occurred. We also have reports while doing a route change with a drawer open. That one thankfully isn't as common as the one mentioned above. Hopefully this info helps finding the bug.

tomas-c commented 1 year ago

I'm also encountering this with the Drawer component and CPU-throttled devices

Ou7law007 commented 11 months ago

I'm facing this with Autocomplete (I think). It's really difficult to reproduce. Version 5.14.0

jimmiebtlr commented 11 months ago

Seeing the same on the @mui/x-date-pickers/DatePicker, I assume they share some code. Doesn't seem to be an opacity on it to hook into.

divmgl commented 9 months ago

I'm running into this problem right now after clicking a MenuItem inside of a Select component if it's wrapped by an outer element which has an equivalent event.stopPropagation() and event.preventDefault() call in the onClick handler. It's a complete showstopper.

I finally looked up "mui backdrop stays open" on Google and found this thread. This solution works but it'd be nice if the backdrop didn't stay permanently open...

spicattutti commented 7 months ago

I implemented the hack @doflo-dfa mentioned in our theme config, so it only applies for the backdrop. This works fine for until the issue gets fixed.

const theme = createTheme({
  // ...
  components: {
    MuiBackdrop: {
      styleOverrides: {
        root: {
          '&[style*="opacity: 0"]': {
            pointerEvents: 'none',
          },
        },
      },
    },
  },
});

I've also found a way to reproduce this bug in a specific instance. If I open https://nextjs-azalp-9294f0bzd-azalp-de.vercel.app/ in browserstack with edge 112, it gets stuck when I double-click on a sub menu item. The open state of the backdrop is controlled by a state that gets set to false on click. Only the main menu items in the blue bar have the ability to change it to true on mouse over. Can't imagine a setState setting it to false running twice could trigger this. Thats also not the only time this bug occurred. We also have reports while doing a route change with a drawer open. That one thankfully isn't as common as the one mentioned above. Hopefully this info helps finding the bug.

To pick up the aforementioned workaround, I had to use

import { backdropClasses } from "@mui/material/Backdrop";

// within createTheme

      MuiModal: {
        styleOverrides: {
          root: {
            [`&:has(> div.${backdropClasses.root}[style*="opacity: 0"])`]: {
              pointerEvents: "none",
            },
          },
        },
      },

Since for me, it was the modal and not the backdrop that blocked pointer events.

Running

"@mui/material": "5.14.4",
"next": "13.5.5",

also observing issue when transitioning to another page by using a Link in a Menu.

dchadcluff commented 5 months ago

This bug just started happening for my project after updating from Remix.run version 1 to version 2.4. I've used the theme hack to get by as well.

racc-oo-n commented 4 months ago

I'm getting the same bug in e2e tests, can't reproduce it manually. Using

"@playwright/test": "^1.41.2",
"@mui/base": "5.0.0-beta.37",
"@mui/lab": "5.0.0-alpha.165",
"@mui/material": "5.15.10",

Testing error

Call log:
  - waiting for getByRole('dialog').getByRole('button', { name: /submit/i })
  -   locator resolved to <button id=":rd:" tabindex="0" type="button" class="MuiB…>…</button>
  - attempting click action
  -   waiting for element to be visible, enabled and stable
  -   element is visible, enabled and stable
  -   scrolling into view if needed
  -   done scrolling
  -   <div aria-hidden="true" class="MuiBackdrop-root MuiBa…></div> from <div id="menu-Status" aria-hidden="true" role="presen…>…</div> subtree intercepts pointer events
  - retrying click action, attempt #1
  -   waiting for element to be visible, enabled and stable
  -   element is visible, enabled and stable
  -   scrolling into view if needed
  -   done scrolling
  -   <div aria-hidden="true" class="MuiBackdrop-root MuiBa…></div> from <div id="menu-Status" aria-hidden="true" role="presen…>…</div> subtree intercepts pointer events
  - retrying click action, attempt #2
  ...

That's happening on the Select component, but the layout is: Page > Drawer > Select. Maybe that's the reason – we have nested Backdrop components.

this solution helped https://github.com/mui/material-ui/issues/32286#issuecomment-1820685334

owenashurst commented 3 months ago

Any solution to this? I'm routing to other pages when this issue occurs (SPA). If I click on the same menu item to route to the same page, it doesn't happen. I have to click twice elsewhere on the page for the backdrop to be removed so I can continue interacting with the page.

The interesting thing is, once I've clicked off twice, and navigate to another page using the drawer, the backdrop works as expected. It seems to be a one off occurrence. If you do a full page refresh, then the issue appears again.

EDIT: If I downgrade from React 18 to React 17 (specifically 17.0.2), I don't see the issue anymore.

MaRaSu commented 2 months ago

I run into the same issue with NextJS 13 and MUI v5, specifically on Android Chrome and Drawer-components in certain (and very repeatable) situations. I had to adapt @spicattutti solution to apply to Drawer as well:

import { backdropClasses } from "@mui/material/Backdrop";

// within createTheme

      MuiDrawer: {
        styleOverrides: {
          root: {
            [`&:has(> div.${backdropClasses.root}[style*="opacity: 0"])`]: {
              pointerEvents: "none",
            },
          },
        },
      },
patricksculley commented 2 months ago

Our users are also effected by this issue (Next 14, Mui 5.15.15). The Dialog component and backdrop are still intermittently rendered on the page with a 0 opacity when the app loads , even though open={false}.

The workaround above does allow the background to be clickable but the page is not scrollable.

This makes the UI unresponsive unless the user refreshes the page. Seems to effect some users more than others.

Upvote for a fix as it makes for a poor app experience.

elfilalime commented 2 months ago

Hello, I am facing the same problem on React 18.2.0 with Mui 5.13.4 or 5.15.15.

I'm using the Menu component which adds BackDrop on opening as expected.

But the strange thing is that the problem never happened before and after N build it only starts happening in production when the project is built. And never in devloppement webpack serve

After 3 days of investigating to find what changes are causing the issue, I discovered that this happens when the bundle size exceeds 1.8 MiB and it has nothing to do with any code I add.

The CSS trick worked fine but the BackDrop and its container are still on DOM.

Waiting for a fix

Thanks