New Web APIs — a popover on top of a dialog element can’t be interacted with?
Imagine an interface. In it, there is a button. You click the button and we launch a new piece of UI over the top of everything. You stay in that ‘upper’ UI until you are done and then dismiss this UI to return whence you came down below.
Got that? Great. How would we build that?
Launching something above everything else for some temporary period of time seemed a perfect use case for the dialog
element.
OK, my understanding of dialog
elements and the top layer at this point…
When you use showModal()
the dialog
in question is promoted to the ‘top layer’. This lives beyond the normal document confines, allowing the contents of the dialog to live above the DOM. The resultant dialog, when using showModal()
is positioned with fixed layout by default and a bunch of user styles. Crucially it also comes with a ::backdrop
pseudo element, which, although you can use inset: unset;
to allow you to move it around, and even though you might stick display: none
on that backdrop pseudo element, the DOM below remains inert as if the backdrop were there anyway.
So, for our ‘upper’ UI, dialog
seems a good fit.
Modal over a modal?
But then what when you need to position something on top of that modal dialog?
Crucially, this extra item isn’t full screen, so doesn’t warrant showModal()
itself. Well, you might think you could use show()
on another sibling dialog instead?
You cannot.
Well, you can, but using show()
does not promote this new ‘top’ dialog
to the Holy Landtop layer. And as z-index
has no powers in or over the top layer, using z-index
is a dead-end, it simply won’t work — seriously, it is futile, OK? With show()
your dialog is shown, but below the lofty heights of the top layer.
‘Screw this’ you think (I sure did), let’s just make this second upper dialog use showModal()
too. That way, if I put it after the first dialog in the DOM, it will surely appear on top?
Yes, but… no.
It appears on top, but have you not been paying attention? Because it is in modal mode, it has a backdrop that even when you kill it off with display: none;
, is un-killable like some Freddie Kruger style nightmare pseudo element. Somehow, the contents below this upper dialog remains dead and inert to you.
You can look at this approach here.
So, is that it? Defeat? Are those dev rels touting this months ‘hot new shizzle’ just full of baloney? Is it back to standard elements and good old z-index: 1000
?
Not on your nelly pal, we got one last thing to try: popovers.
Even newer than the newish dialog element is the popover API, which at first glance looks like it might be just the ticket.
The Popover API provides developers with a standard, consistent, flexible mechanism for displaying popover content on top of other page content.
Popover API to the rescue?
So, I refactored things a little, changed the second dialog
element to a div
with the popover
attribute. And then rewired the JS to show and hide the new fangled popover instead:
launchTop.addEventListener("click", () => {
if (isTopShowing) {
isTopShowing = false;
topDog.hidePopover();
} else {
isTopShowing = true;
topDog.showPopover();
}
});
You can look at his one here.
At first I was elated. I launched the first dialog
in modal mode, and I then clicked the button to launch the popover from the modal and there it was, the popover. I clicked the button on the original modal again and it disappeared. Wow, fantastic, love these new APIs (narrator: “little did he know, he was soon to be swearing at these new APIs”).
That it? Kiss the dame and roll credits? Sadly, this story doesn’t have a happy ending (yet?).
Here is the kicker. You can’t do anything with the contents of this popover when it is sat on top of a modal dialog. Even though you can see the popup, you cannot interact with it. Try clicking the ‘Close Me’ in that example.
However, as soon as you close that dialog, so that you are left with the bottom UI and the popover, you can now interact with the popover as you might expect.
The end
And so here I end this tale of woe, hoping the entirely probable likelihood exists, that I am merely “doing it wrong”. Please, someone, enlighten me.
On the face of it, and admittedly coming at this from a position of rushed naivety, this seems ‘broken’. All this ‘top layer’ stuff is all well and good, but can someone explain, how one has something in a top layer, and then another item above that, that can actually be interacted with?
As ever I’m expected to be schooled on the right way to do this. For now I opened a bug report for Chromium
If it can’t, then there are going to be an awful lot more devs that will continue opting for good ol’ divs and z-index: 1000
.
Hi,
I came across your article as I was having the same problem, trying to get a popover element to be interactive after being opened from within a dialog.
The div element with the popover attribute was located outside of the dialog element. The button on the popover was inert until I closed the modal dialog and only then was the button active again.
But, if you put the popover element INSIDE of the dialog, the popover’s buttons and input elements will be accessible when the popover is opened from the dialog. My understanding is that any element outside of the modal dialog would be inert, so it stands to reason that anything within the dialog would be functional.