ui
ui copied to clipboard
Overlay immediately closes with rootClose in shadow root
Describe the bug
Overlay with rootClose closes as soon as it is opened if it is hosted inside of a custom element shadow root.
I'm using custom elements to isolate some react based components that are hosted in an older application. The Overlay immediately closes when opened if it is hosted inside of a shadow root of a custom element. The same code works correctly when hosted in the light dom.
To Reproduce
Steps to reproduce the behavior:
- Create a custom element with a shadow root that hosts a react render root
- Render a Overlay with
rootCloseandonHideset. Also have thecontaineroption point to an element in the shadow root - Click the button to open the overlay.
Reproducible Example
https://codesandbox.io/s/bold-dan-5kfh5r - Declares a custom element in index.js and has it render the same React component as is rendered in the light DOM. The custom element embedded version does not work, the light DOM version does.
- Click the Show in shadow root button. Note the popover flashes and then disappears.
- Click Show in light DOM button. Note that the popover appears and remains visibile.
Expected behavior
The popover remains open until an additional click.
Screenshots
Screencast from 08-08-2023 10:04:38 AM.webm
Environment (please complete the following information)
- Operating System: Linux
- Browser, Version: Chrome 115.0.5790.110
Additional context
This seems to be related to a change between React 17 and React 18. Was not able to reproduce it using React 17 or the legacy ReactDOM.render method in React 18.
The original workaround that @jquense added to fix this doesn't work in the shadow DOM because currentEvent is undefined
https://github.com/react-restart/ui/blob/44dc346744b37c33bd0d0309e5cd827751fce9c4/src/useClickOutside.ts#L104C9-L104C9
As a result, the click handler is processing twice
Funny I just saw that material UI has a different work around for the same issue in their ClickAway component, maybe we can try that?
Funny I just saw that material UI has a different work around for the same issue in their ClickAway component, maybe we can try that?
Unfortunately couldn't get tests to pass with the MUI approach. I'll need to drop this for now, since I'm short on time ATM.
fair enough, i don't think this is a super pressing use case anyway!
Hi, any update? Do you need some help to make test passing? I'd like to make it work as soon as possible as the whole react-bootstrap is not working in the shadowDOM.
This issue is also visible for Dropdowns. In the shadow tree, dropdown is opened and immediately closed.
FYI @mklekowski I ended up working around this by not using rootClose and then adding my own event listeners for Escape and a click outside the overlay.
Actually, I have an issue with DropdownButton, when clicking two events are triggered, first for opening and second for closing. Probably it's also possible to disable rootClose and implement it manually, but I prefer to fix it in the library directly.
@jquense can you look at the issue?
Also, the code is using Window/event which is deprecated. Maybe it can be implemented in different way?
Actually, I have an issue with DropdownButton, when clicking two events are triggered, first for opening and second for closing. Probably it's also possible to disable rootClose and implement it manually, but I prefer to fix it in the library directly.
@mklekowski do you have a workaround? I have the same issue as you, with DropdownButton.
Yes and no :) The workaround for me was to change usage of the library to mui/base-ui - it has better support for shadow dom and it looks like it's better maintained.
Yes and no :) The workaround for me was to change usage of the library to mui/base-ui - it has better support for shadow dom and it looks like it's better maintained.
Ouch - thank you anyway - I'm bound to Bootstrap though, so hopefully this gets fixed soon. My current workaround is
<Dropdown
autoClose="outside"
show={showDropdown}
onToggle={(show, meta) => {
const target = meta.originalEvent?.target as HTMLElement;
if (target.tagName !== "DROP-DOWN") { // "drop-down" is my custom element name
setShowDropdown(show);
}
}}
>
</Dropdown>
This makes the Dropdown kinda work, but it doesn't close the menu when you click inside the custom element but outside the button.