bug(popups): Material popups shown from native HTML dialog appear behind dialog
Is this a regression?
- [ ] Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
No response
Description
When components that display a popup (like Select or DateTIme) are placed inside a native HTML dialog, the popup appears behind the dialog rather than inside or in front of it.
Reproduction
Steps to reproduce:
- Open this StackBlitz
- Click the button to show the dialog
- Click on the select and/or the calendar button
Expected Behavior
The popup for the select and calendar are visible in front of the dialog and are interactable.
Actual Behavior
The popups are obscured behind the dialog. The parts that appear behind it are not interactive because of the dialog overlay.
Environment
- Angular: 14.1.3 (also reproduced in 12)
- CDK/Material: 14.1.3
- Browser(s): Reproduced in Safari, Firefox, and Chromium
- Operating System: macOS
Possible workaround: if the component is added to the dialog when the dialog is already open, the popups correctly appear in front of the dialog. You can see this in the StackBlitz linked above by adding the open attribute to the <dialog> element.
This is definitely a problem, but as far as I can tell, there's no way around it. The problem is that native dialog elements are inserted into a special "top layer" that will be on top of everything, see: https://developer.chrome.com/blog/what-is-the-top-layer/. The top layer isn't affected by things like z-index so there's no way for us to put our overlay container on top. I was playing with the ideas to either briefly open and close the native dialogs or to use a dialog element for the overlay container, but both of these approaches will be problematic for accessibility.
Both the CDK and Material include their own dialog implementations that you can use instead of the native one and which will stack correctly.
I've drag&dropped the .cdk-overlay-container into the dialog, it seems to fix the issue :D
I hardly believe it's a decent solution, hovever could the dialog element provide an Overlay instance that's rendered inside of it?
It does work, but I think that it'll be problematic for accessibility as well.
@crisbeto Could you elaborate on why using a new overlay instance would affect accessibility?
If we put everything in a dialog element, my understanding is that the browser will present it as a dialog to assistive technology. Most of our overlay-based components use patterns different from dialog.
If we put everything in a
dialogelement, my understanding is that the browser will present it as a dialog to assistive technology. Most of our overlay-based components use patterns different fromdialog.
@crisbeto Thank you very much for explaining. This helps us @jattasNI move forward.
As @Totati also mentioned, dragging & dropping it inside the dialog seems to solve the issue and as far as I've tested it works fine. This can be done through the typescript code by making the dialog the parent element of the overlay container after the dialog has rendered. After the dialog is closed, make sure the parent element is set back to what it was initially
@stefanc18 could we please supply us with a sample code of this case, been struggling with this for a few days now. Thanks in advance.
As a quick solution it would be nice to have an option not to use the global OverlayContainer, but instead an override such as inside the dialog.
As a long term solution, I believe this new dialog tag is solving fundamental issues that led to creating the complex Overlay component in the first place. Now that we have easy access to the top layer from anywhere in our application just with HTML, I believe the Overlay will need a complete rewrite.
If anyone finds a temporary fix for this, please let me know 👍