The HTML popover
attribute transforms elements into top-layer elements that can be opened and closed with a button or JavaScript. Most popovers can be light-dismissed, closing when the user clicks or taps outside the popup. Currently, HTML popover
lacks built-in auto-close functionality, but it’s easy to add. Auto closing popups are useful for user interfaces like banner notifications — the new-message alerts in phones, for instance.
A picture demo, is worth a thousand words, right? Click on the “Add to my bookmarks” button in the following example. It triggers a notification that dismisses itself after a set amount of time.
Let’s start with the popover
The HTML popover
attribute is remarkably trivial to use. Slap it on a div
, specify the type of popover you need, and you’re done.
<div popover="manual" id="pop">Bookmarked!</div>
A manual
popover simply means it cannot be light-dismissed by clicking outside the element. As a result, we have to hide, show, or toggle the popover’s visibility ourselves explicitly with either buttons or JavaScript. Let’s use a semantic HTML button
.
<button popovertarget="pop" popovertargetaction="show">
Add to my bookmarks
</button>
<div popover="manual" id="pop">Bookmarked!</div>
The popovertarget
and popovertargetaction
attributes are the final two ingredients, where popovertarget
links the button to the popover
element and popovertargetaction
ensures that the popover
is show
-n when the button is clicked.
Hiding the popover with a CSS transition
OK, so the challenge is that we have a popover
that is shown when a certain button is clicked, but it cannot be dismissed. The button is only wired up to show
the popover
, but it does not hide
or toggle
the popover
(since we are not explicitly declaring it). We want the popover
to show
when the button is clicked, then dismiss itself after a certain amount of time.
The HTML popover
can’t be closed with CSS, but it can be hidden from the page. Adding animation to that creates a visual effect. In our example, we will hide the popover
by eliminating its CSS height
property. You’ll learn in a moment why we’re using height
, and that there are other ways you can go about it.
We can indeed select the popover
attribute using an attribute selector:
[popover] {
height: 0;
transition: height cubic-bezier(0.6, -0.28, 0.735, 0.045) .3s .6s;
@starting-style {
height: 1lh;
}
}
When the popover
is triggered by the button, its height
value is the one declared in the @starting-style
ruleset (1lh
). After the transition-delay
(which is .6s
in the example), the height
goes from 1lh
to 0
in .3s
, effectively hiding the popover
.
Once again, this is only hiding the popover, not closing it properly. That’s the next challenge and we’ll need JavaScript for that level of interaction.
Closing the popover with JavaScript
We can start by setting a variable that selects the popover
:
const POPOVER = document.querySelector('[popover]');
Next, we can establish a ResizeObserver
that monitors the popover
’s size:
const POPOVER = document.querySelector('[popover]');
const OBSERVER =
new ResizeObserver((entries) => {
if(entries[0].contentBoxSize[0].blockSize == 0)
OBSERVER.unobserve((POPOVER.hidePopover(), POPOVER));
});
And we can fire that off starting when the button to show the popover
is clicked:
const POPOVER = document.querySelector('[popover]');
const OBSERVER =
new ResizeObserver((entries) => {
if(entries[0].contentBoxSize[0].blockSize == 0)
OBSERVER.unobserve((POPOVER.hidePopover(), POPOVER));
});
document.querySelector('button').onclick = () => OBSERVER.observe(POPOVER);
The observer will know when the popover
’s CSS height
reaches zero at the end of the transition, and, at that point, the popover
is closed with hidePopover()
. From there, the observer is stopped with unobserve()
.
In our example, height
and ResizeObserver
are used to auto-close the notification. You can try any other CSS property and JavaScript observer combination that might work with your preference. Learning about ResizeObserver
and MutationObserver
can help you find some options.
Setting an HTML fallback
When JavaScript is disabled in the browser, if the popover
type is set to any of the light-dismissible types, it acts as a fallback. Keep the popover
visible by overriding the style rules that hide it. The user can dismiss it by clicking or tapping anywhere outside the element.
If the popover
needs to be light-dismissible only when JavaScript is disabled, then include that popover
inside a <noscript>
element before the manual
popover. It’s the same process as before, where you override CSS styles as needed.
<noscript>
<div popover="auto" id="pop">Bookmarked!</div>
</noscript>
<div popover="manual" id="pop">Bookmarked!</div>
<!-- goes where <head> element's descendants go -->
<noscript>
<style>
[popover] {
transition: none;
height: 1lh;
}
</style>
</noscript>
When to use this method?
Another way to implement all of this would be to use setTimeout()
to create a delay before closing the popover in JavaScript when the button is clicked, then adding a class to the popover
element to trigger the transition effect. That way, no observer is needed.
With the method covered in this post, the delay can be set and triggered in CSS itself, thanks to @starting-style
and transition-delay
— no extra class required! If you prefer to implement the delay through CSS itself, then this method works best. The JavaScript will catch up to the change CSS makes at the time CSS defines, not the other way around.
Creating an Auto-Closing Notification With an HTML Popover originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.