The Popover API enters Baseline

The Popover API is now available across all modern browsers and is officially part of Baseline 2024. This API gives developers a set of primitives for building layered interfaces—tooltips, menus, teaching UIs, and similar components—without having to rely on custom JavaScript for every piece of behavior.

Key capabilities of the API include:

  • Top-layer promotion. Popovers render in the top layer above the rest of the page, removing the need to manage z-index.
  • Light-dismiss. Clicking outside the popover closes it and returns focus.
  • Built-in focus management. Opening a popover moves the next tab stop into the popover.
  • Accessible keyboard handling. Pressing esc or toggling the trigger closes the popover and returns focus.
  • Semantic component linking. Triggers can be connected to popover elements declaratively.

Creating a popover

Building a popover with default settings requires only a trigger button and a target element. Set the popover attribute on the target element, give it a unique id, and then wire the button to it using the popovertarget attribute set to that id:

<button popovertarget="my-popover">Open Popover</button>

<div id="my-popover" popover>
  <p><p>I am a popover with more information. Hit <kbd>esc</kbd> or click away to close me.<p></p>
</div>

Popovers can also be configured with explicit types. Using popover="auto"—which is the same as the bare popover attribute—enables light-dismiss behavior and automatically closes any other open popovers. The popover="manual" type skips those conveniences; manual popovers do not close other popovers, do not react to outside clicks, and need an explicit close control. A manual popover is set up like this:

<button popovertarget="my-popover" class="trigger-btn"> Open Popover </button>

<div id="my-popover" popover=manual>
  <p>I am a popover with more information. Hit the close button or toggle to close me.<p>
  <button class="close-btn" popovertarget="my-popover" popovertargetaction="hide">
    <span aria-hidden="true">❌</span>
    <span class="sr-only">Close</span>
  </button>
</div>

Popovers vs. modal dialogs

Given that <dialog> already exists, it's worth clarifying when popovers are the right tool. The popover attribute adds no semantics of its own; it is purely a presentational and behavioral primitive. If you need to block interaction with the rest of the page, a modal dialog is still the appropriate choice.

The modal <dialog> element:

  • Opened with dialog.showModal() and closed with dialog.close().
  • Makes the rest of the page inert when open.
  • Does not support light-dismiss behavior.
  • Can be styled using the [open] attribute selector.
  • Carries semantics for an interactive component that blocks page interaction.

The [popover] attribute:

  • Can be opened declaratively with popovertarget.
  • Is closed via popovertarget (for auto popovers) or popovertargetaction=hide (for manual popovers).
  • Does not make the rest of the page inert.
  • Supports light-dismiss behavior.
  • Can be styled when open using the :popover-open pseudo-class.
  • Has no inherent semantics.

Further reading

For a deeper look at popover semantics, accessibility behavior, and the full API surface, these resources are a good starting point: