Movatterモバイル変換


[0]ホーム

URL:


MDN Web Docs

Using the Popover API

ThePopover API provides developers with a standard, consistent, flexible mechanism for displaying popover content on top of other page content. Popover content can be controlled either declaratively using HTML attributes, or via JavaScript. This article provides a detailed guide to using all of its features.

Creating declarative popovers

In its simplest form, a popover is created by adding thepopover attribute to the element that you want to contain your popover content. Anid is also needed to associate the popover with its controls.

html
<div popover>Popover content</div>

Note:Setting thepopover attribute with no value is equivalent to settingpopover="auto".

Adding this attribute causes the element to be hidden on page load by havingdisplay: none set on it. To show/hide the popover, you need to add at least one control button (also know as the popoverinvoker). You can set a<button> (or<input> oftype="button") as a popover control button by giving it apopovertarget attribute, the value of which should be the ID of the popover to control:

html
<button popovertarget="mypopover">Toggle the popover</button><div popover>Popover content</div>

The default behavior is for the button to be a toggle button — pressing it repeatedly will toggle the popover between showing and hidden.

If you want to change that behavior, you can use thepopovertargetaction attribute — this takes a value of"hide","show", or"toggle". For example, to create separate show and hide buttons, you could do this:

html
<button popovertarget="mypopover" popovertargetaction="show">  Show popover</button><button popovertarget="mypopover" popovertargetaction="hide">  Hide popover</button><div popover>Popover content</div>

You can see how the previous code snippet renders in ourBasic declarative popover example (source).

Note:If thepopovertargetaction attribute is omitted,"toggle" is the default action that will be performed by a control button.

When a popover is shown, it hasdisplay: none removed from it and it is put into thetop layer so it will sit on top of all other page content.

auto state, and "light dismiss"

When a popover element is set withpopover orpopover="auto" as shown above, it is said to haveauto state. The two important behaviors to note about auto state are:

  • The popover can be "light dismissed" — this means that you can hide the popover by clicking outside it.
  • The popover can also be closed, using browser-specific mechanisms such as pressing theEsc key.
  • Usually, only oneauto popover can be shown at a time — showing a second popover when one is already shown will hide the first one. The exception to this rule is when you have nested auto popovers. See theNested popovers section for more details.

Note:popover="auto" popovers are also dismissed by successfulHTMLDialogElement.showModal() andElement.requestFullscreen() calls on other elements in the document. Bear in mind however that calling these methods on a shown popover will result in failure because those behaviors don't make sense on an already-shown popover. You can however call them on an element with thepopover attribute that isn't currently being shown.

Auto state is useful when you only want to show a single popover at once. Perhaps you have multiple teaching UI messages that you want to show, but don't want the display to start getting cluttered and confusing, or perhaps you are showing status messages where the new status overrides any previous status.

You can see the behavior described above in action in ourMultiple auto popovers example (source). Try light dismissing the popovers after they are shown, and see what happens when you try to show both at the same time.

Popover accessibility features

When a relationship is established between a popover and its control (invoker) via thepopovertarget attribute, the API automatically makes two other changes to the environment to allow keyboard and assistive technology (AT) users to more easily interact with the popover:

  • When the popover is shown, the keyboard focus navigation order is updated so that the popover is next in the sequence: for example, when a button is pressed to show a popover, any buttons inside the popover will be next in the tabbing order (will be focused by pressing theTab key). Conversely, when closing the popover via the keyboard (usually via theEsc key), focus is shifted back to the invoker.
  • To allow AT such as screen readers to make sense of the relationship between the invoker and the popover, an implicitaria-details andaria-expanded relationship is set up between them.

Setting up a relationship between a popover and its control in this manner also creates an implicit anchor reference between the two — seePopover anchor positioning for more details.

Other ways to set up a popover-invoker relationship

You can set up a popover-invoker relationship in other ways, in addition to using thepopovertarget attribute:

  • Using thesource option of theHTMLElement.showPopover() orHTMLElement.togglePopover() methods. Bear in mind that in this case, only the focus navigation order changes are made, not the implicit ARIA relationship. This because thesource option can be set to any kind of element, not just<button> elements, and it cannot be guaranteed that the relationship would make sense.
  • Between a<select> element and its dropdown picker, when opting it intocustomizable select element functionality via theappearance propertybase-select value. In this case, an implicit popover-invoker relationship is created between the two.

Using manual popover state

One alternative to auto state ismanual state, achieved by settingpopover="manual" on your popover element:

html
<div popover="manual">Popover content</div>

In this state:

  • The popover cannot be "light dismissed", although declarative show/hide/toggle buttons (as seen earlier) will still work.
  • Multiple independent popovers can be shown simultaneously.

You can see this behavior in action in ourMultiple manual popovers example (source).

Showing popovers via JavaScript

You can also control popovers using a JavaScript API.

TheHTMLElement.popover property can be used to get or set thepopover attribute. This can be used to create a popover via JavaScript, and is also useful for feature detection. For example:

js
function supportsPopover() {  return Object.hasOwn(HTMLElement.prototype, "popover");}

Similarly:

Putting these three together, you can programmatically set up a popover and its control button, like so:

js
const popover = document.getElementById("mypopover");const toggleBtn = document.getElementById("toggleBtn");const keyboardHelpPara = document.getElementById("keyboard-help-para");const popoverSupported = supportsPopover();if (popoverSupported) {  popover.popover = "auto";  toggleBtn.popoverTargetElement = popover;  toggleBtn.popoverTargetAction = "toggle";} else {  toggleBtn.style.display = "none";}

You also have several methods to control showing and hiding:

For example, you might want to provide the ability to toggle a help popover on and off by clicking a button or pressing a particular key on the keyboard. The first one could be achieved declaratively, or you could do it using JavaScript as shown above.

For the second one, you could create an event handler that programs two separate keys — one to open the popover and one to close it again:

js
document.addEventListener("keydown", (event) => {  if (event.key === "h") {    if (popover.matches(":popover-open")) {      popover.hidePopover();    }  }  if (event.key === "s") {    if (!popover.matches(":popover-open")) {      popover.showPopover();    }  }});

This example usesElement.matches() to programmatically check whether a popover is currently showing. The:popover-open pseudo-class matches only popovers that are currently being shown. This is important to avoid the errors that are thrown if you try to show an already-shown popover, or hide an already-hidden popover.

Alternatively, you could program a single key to showand hide the popover like this:

js
document.addEventListener("keydown", (event) => {  if (event.key === "h") {    popover.togglePopover();  }});

See ourToggle help UI example (source) to see the popover JavaScript properties, feature detection, andtogglePopover() method in action.

Nested popovers

There is an exception to the rule about not displaying multiple auto popovers at once — when they are nested inside one another. In such cases, multiple popovers are allowed to both be open at the same time, due to their relationship with each other. This pattern is supported to enable use cases such as nested popover menus.

There are three different ways to create nested popovers:

  1. Direct DOM descendants:

    html
    <div popover>  Parent  <div popover>Child</div></div>
  2. Via invoking/control elements:

    html
    <div popover>  Parent  <button popovertarget="foo">Click me</button></div><div popover>Child</div>
  3. Via theanchor attribute:

    html
    <div popover>Parent</div><div popover anchor="foo">Child</div>

See ourNested popover menu example (source) for an example. You'll notice that quite a few event handlers have been used to display and hide the subpopover appropriately during mouse and keyboard access, and also to hide both menus when an option is selected from either. Depending on how you handle loading of new content, either in an SPA or multi-page website, some of all of these may not be necessary, but they have been included in this demo for illustrative purposes.

Using "hint" popover state

There is a third type of popover you can create —hint popovers, designated by settingpopover="hint" on your popover element.hint popovers do not closeauto popovers when they are displayed, but will close otherhint popovers. They can be light dismissed and will respond to close requests.

This is useful for situations where, for example, you have toolbar buttons that can be pressed to show UI popovers, but you also want to reveal tooltips when the buttons are hovered, without closing the UI popovers.

hint popovers tend to be shown and hidden in response to non-click JavaScript events such asmouseover/mouseout andfocus/blur. Clicking a button to open ahint popover would cause an openauto popover to light-dismiss.

See ourpopover hint demo (source) for an example that behaves exactly as described above. The demo features a button bar; when pressed, the buttons showauto popup sub-menus inside which further options can be selected. However, when hovered over or focused, the buttons also show tooltips (hint popovers) to give the user an idea of what each button does, which do not hide a currently-showing sub-menu.

In the below sections, we'll walk through all the important parts of the code.

Note:Youcan usehint popovers alongsidemanual popovers, although there is not really much of a reason to. They are designed to circumvent some of the limitations ofauto popovers, enabling use cases like the one detailed in this section.

Note also thatpopover="hint" falls back topopover="manual" in unsupporting browsers.

Creating the sub-menus withpopover="auto"

The popup sub-menus are created declaratively, usingauto popovers.

First, the control buttons:

html
<section>  <button popovertarget="submenu-1" popovertargetaction="toggle">    Menu A  </button>  <button popovertarget="submenu-2" popovertargetaction="toggle">    Menu B  </button>  <button popovertarget="submenu-3" popovertargetaction="toggle">    Menu C  </button></section>

Now, the popovers themselves:

html
<div popover="auto">  <button>Option A</button><br /><button>Option B</button></div><div popover="auto">  <button>Option A</button><br /><button>Option B</button></div><div popover="auto">  <button>Option A</button><br /><button>Option B</button></div>

Creating the tooltips withpopover="hint"

The sub-menu popovers work fine as they are, opening when the toolbar buttons are pressed, but how do we also show tooltips on button hover/focus? First, we create the tooltips in HTML, usinghint popovers:

html
<div popover="hint">Tooltip A</div><div popover="hint">Tooltip B</div><div popover="hint">Tooltip C</div>

To control the showing/hiding, we need to use JavaScript. First of all, we grab references to thehint popovers and the control buttons in two separateNodeLists usingDocument.querySelectorAll():

js
const tooltips = document.querySelectorAll(".tooltip");const btns = document.querySelectorAll("#button-bar button");

Next, we create a function,addEventListeners(), which sets four event listeners (viaEventTarget.addEventListener()) on a given<button>, chosen by grabbing the<button> at a specific index value of thebtnsNodeList. The functions act on thehint popover at the same index value of thetooltipsNodeList, allowing us to keep the buttons and the tooltips in sync — showing/hiding the correct tooltip when a button is interacted with.

The event listenersshow the popover onmouseover andfocus, andhide the popover onmouseout andblur, meaning that the tooltips can be accessed via mouse and keyboard.

js
function addEventListeners(i) {  btns[i].addEventListener("mouseover", () => {    tooltips[i].showPopover({ source: btns[i] });  });  btns[i].addEventListener("mouseout", () => {    tooltips[i].hidePopover();  });  btns[i].addEventListener("focus", () => {    tooltips[i].showPopover({ source: btns[i] });  });  btns[i].addEventListener("blur", () => {    tooltips[i].hidePopover();  });}

Finally, we use afor loop to iterate through the<buttons> in thebtnsNodeList, calling theaddEventListeners() function for each one so that all of them have the desired event listeners set.

js
for (let i = 0; i < btns.length; i++) {  addEventListeners(i);}

Styling popovers

This section covers some CSS selection and positioning techniques relevant to popovers.

Selecting popovers

You can select all popovers with a simple attribute selector:

css
[popover] {  /* Declarations here */}

Alternatively, you can select a specific popover type by including a value in the attribute selector:

css
[popover="auto"] {  /* Declarations here */}

You can select only popovers that are showing using the:popover-open pseudo-class:

css
:popover-open {  /* Declarations here */}

Styling the popover backdrop

The::backdrop pseudo-element is a full-screen element placed directly behind showing popover elements in thetop layer, allowing effects to be added to the page content behind the popover(s) if desired. You might for example want to blur out the content behind the popover to help focus the user's attention on it:

css
::backdrop {  backdrop-filter: blur(3px);}

See ourPopover blur background example (source) for an idea of how this renders.

Positioning popovers

When looking at the first couple of examples linked at the start of the article, you may have noticed that the popovers appear in the middle of the viewport, wrap their content, and have a black border. This is the default styling, achieved using the following rule in the UA stylesheet:

css
[popover] {  position: fixed;  inset: 0;  width: fit-content;  height: fit-content;  margin: auto;  border: solid;  padding: 0.25em;  overflow: auto;  color: CanvasText;  background-color: Canvas;}

To apply custom sizing and position the popover somewhere else, you could override the above styles with something like this:

css
:popover-open {  width: 200px;  height: 100px;  position: absolute;  inset: unset;  bottom: 5px;  right: 5px;  margin: 0;}

You can see an isolated example of this in ourPopover positioning example (source).

Popover anchor positioning

There is another useful positioning option that the Popover API provides. If you want to position a popover relative to its invoker rather than the viewport or a positioned ancestor, you can take advantage of the fact that popovers and their invokers have animplicit anchor reference.

Associating any kind of popover with its invoker creates an implicit anchor reference between the two. This causes the invoker to become the popover'sanchor element, meaning that you can position the popover relative to it usingCSS anchor positioning.

Because the association between the popover and the invoker is implicit, an explicit association does not need to be made using theanchor-name andposition-anchor properties. However, you still need to specify the positioning CSS.

For example, you could use a combination ofanchor() function values set oninset properties, andanchor-center values set on alignment properties:

css
.my-popover {  bottom: calc(anchor(top) + 20px);  justify-self: anchor-center;}

Or you could use aposition-area property:

css
.my-popover {  position-area: top;}

SeeUsing CSS anchor positioning for more details on associating anchor and positioned elements, and positioning elements relative to their anchor.

Note:For an example that uses this implicit association, see ourpopover hint demo (source). If you check out the CSS code, you'll see that no explicit anchor associations are made using theanchor-name andposition-anchor properties.

Animating popovers

Popovers are set todisplay: none; when hidden anddisplay: block; when shown, as well as being removed from / added to thetop layer and theaccessibility tree. Therefore, for popovers to be animated, thedisplay property needs to be animatable.Supporting browsers animatedisplay with a variation on thediscrete animation type. Specifically, the browser will flip betweennone and another value ofdisplay so that the animated content is shown for the entire animation duration. So, for example:

  • When animatingdisplay fromnone toblock (or another visibledisplay value), the value will flip toblock at0% of the animation duration so it is visible throughout.
  • When animatingdisplay fromblock (or another visibledisplay value) tonone, the value will flip tonone at100% of the animation duration so it is visible throughout.

Note:When animating usingCSS transitions,transition-behavior: allow-discrete needs to be set to enable the above behavior. When animating withCSS animations, the above behavior is available by default; an equivalent step is not required.

Transitioning a popover

When animating popovers with CSS transitions, the following features are required:

@starting-style at-rule

Provides a set of starting values for properties set on the popover that you want to transition from when it is first shown. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on an element's first style update, or when thedisplay type changes fromnone to another type.

display property

Adddisplay to the transitions list so that the popover will remain asdisplay: block (or another visibledisplay value) for the duration of the transition, ensuring the other transitions are visible.

overlay property

Includeoverlay in the transitions list to ensure the removal of the popover from the top layer is deferred until the transition completes, again ensuring the transition is visible.

transition-behavior property

Settransition-behavior: allow-discrete on thedisplay andoverlay transitions (or on thetransition shorthand) to enable discrete transitions on these two properties that are not by default animatable.

Let's have a look at an example so you can see what this looks like:

HTML

The HTML contains a<div> element declared to be a popover via the globalpopover HTML attribute, and a<button> element designated as the popover's display control:

html
<button popovertarget="mypopover">Show the popover</button><div popover="auto">I'm a Popover! I should animate.</div>

CSS

The two popover properties we want to transition areopacity andtransform. We want the popover to fade in or out while growing or shrinking horizontally. To achieve this, we set a starting state for these properties on the hidden state of the popover element (selected with the[popover]attribute selector) and an end state for the shown state of the popover (selected via the:popover-open pseudo-class). We also use thetransition property to define the properties to animate and the animation's duration as the popover gets shown or hidden.

css
html {  font-family: Arial, Helvetica, sans-serif;}/* Transition for the popover itself */[popover]:popover-open {  opacity: 1;  transform: scaleX(1);}[popover] {  font-size: 1.2rem;  padding: 10px;  /* Final state of the exit animation */  opacity: 0;  transform: scaleX(0);  transition:    opacity 0.7s,    transform 0.7s,    overlay 0.7s allow-discrete,    display 0.7s allow-discrete;  /* Equivalent to  transition: all 0.7s allow-discrete; */}/* Needs to be after the previous [popover]:popover-open ruleto take effect, as the specificity is the same */@starting-style {  [popover]:popover-open {    opacity: 0;    transform: scaleX(0);  }}/* Transition for the popover's backdrop */[popover]::backdrop {  background-color: rgb(0 0 0 / 0%);  transition:    display 0.7s allow-discrete,    overlay 0.7s allow-discrete,    background-color 0.7s;  /* Equivalent to  transition: all 0.7s allow-discrete; */}[popover]:popover-open::backdrop {  background-color: rgb(0 0 0 / 25%);}/* The nesting selector (&) cannot represent pseudo-elementsso this starting-style rule cannot be nested */@starting-style {  [popover]:popover-open::backdrop {    background-color: rgb(0 0 0 / 0%);  }}

As discussed earlier, we have also:

  • Set a starting state for thetransition inside the@starting-style block.
  • Addeddisplay to the list of transitioned properties so that the animated element is visible (set todisplay: block) throughout the popover's entry and exit animations. Without this, the exit animation would not be visible; in effect, the popover would just disappear.
  • Addedoverlay to the list of transitioned properties to make sure that the removal of the element from the top layer is deferred until the animation has been completed. The effect of this may not be noticeable for basic animations such as this one, but in more complex cases, omitting this property can result in the element being removed from the overlay before the transition completes.
  • Setallow-discrete on both properties in the above transitions to enablediscrete transitions.

You'll note that we've also included a transition on the::backdrop appearing behind the popover when it opens, providing a nice darkening animation.

Result

The code renders as follows:

Note:Because popovers change fromdisplay: none todisplay: block each time they are shown, the popover transitions from its@starting-style styles to its[popover]:popover-open styles every time the entry transition occurs. When the popover closes, it transitions from its[popover]:popover-open state to the default[popover] state.

It is possible for the style transition on entry and exit to be different in such cases. See ourDemonstration of when starting styles are used example for a proof of this.

A popover keyframe animation

When animating a popover with CSS keyframe animations, there are some differences to note:

  • You don't provide a@starting-style; you include your "to" and "from"display values in keyframes.
  • You don't explicitly enable discrete animations; there is no equivalent toallow-discrete inside keyframes.
  • You don't need to setoverlay inside keyframes either; thedisplay animation handles the animation of the popover from shown to hidden.

Let's look at an example.

HTML

The HTML contains a<div> element declared as a popover, and a<button> element designated as the popover's display control:

html
<button popovertarget="mypopover">Show the popover</button><div popover="auto">I'm a Popover! I should animate.</div>

CSS

We have defined keyframes that specify the desired entry and exit animations, and an entry animation for the backdrop only. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the popover is closed, so there is nothing to animate.

css
html {  font-family: Arial, Helvetica, sans-serif;}[popover] {  font-size: 1.2rem;  padding: 10px;  animation: fade-out 0.7s ease-out;}[popover]:popover-open {  animation: fade-in 0.7s ease-out;}[popover]:popover-open::backdrop {  animation: backdrop-fade-in 0.7s ease-out forwards;}/* Animation keyframes */@keyframes fade-in {  0% {    opacity: 0;    transform: scaleX(0);  }  100% {    opacity: 1;    transform: scaleX(1);  }}@keyframes fade-out {  0% {    opacity: 1;    transform: scaleX(1);    /* display needed on the closing animation to keep the popover    visible until the animation ends */    display: block;  }  100% {    opacity: 0;    transform: scaleX(0);    /* display: none not required here because it is the default value    for a closed popover, but including it so the behavior is clear */    display: none;  }}@keyframes backdrop-fade-in {  0% {    background-color: rgb(0 0 0 / 0%);  }  100% {    background-color: rgb(0 0 0 / 25%);  }}

Result

The code renders as follows:

Help improve MDN

Learn how to contribute.

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp