HTML Popover API: Popovers Without JavaScript

Small popups are everywhere on the web. They are used for menus, help text, filters, account controls, share buttons, and many other things.

For years, building one usually meant writing JavaScript to open it, close it, listen for the Escape key, and detect clicks outside the popup.

The HTML Popover API changes that.

For many simple cases, you can now create a popover with HTML and CSS only.

The simplest popover

Here is a complete example:

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

<div id="my-popover" popover>
  Hello from a native popover.
</div>

That is enough.

Click the button and the popover opens. Click outside it or press Escape and it closes.

There is no JavaScript.

The Popover API is now available across current browsers, although older browsers may still need a fallback.

How it works

There are two important parts.

The popover itself:

<div id="menu" popover>
  ...
</div>

And the button that points to it:

<button popovertarget="menu">
  Menu
</button>

The popovertarget value matches the id of the popover.

The browser handles the connection.

A simple menu

A menu can be built like this:

<button popovertarget="main-menu">
  Menu
</button>

<nav id="main-menu" popover>
  <a href="/">Home</a>
  <a href="/blogs/">Blog</a>
  <a href="/projects/">Projects</a>
  <a href="/contact/">Contact</a>
</nav>

Then style it:

#main-menu {
  border: 1px solid #ddd;
  border-radius: 0.5rem;
  padding: 1rem;
}

#main-menu:popover-open {
  display: grid;
  gap: 0.75rem;
}

The :popover-open pseudo-class only matches while the popover is open.

You can style the backdrop

Popovers can use ::backdrop too:

#main-menu::backdrop {
  background: rgb(0 0 0 / 0.2);
}

This is useful when you want the rest of the page to look darker while the popover is open.

For many small menus, I would leave the backdrop transparent. It depends on the design.

Auto popovers

The default type is auto.

These two examples mean the same thing:

<div popover>
  Content
</div>
<div popover="auto">
  Content
</div>

An auto popover can be closed by clicking outside it or pressing Escape.

Usually, opening another auto popover closes the first one.

That behaviour is useful for menus and tool panels because the browser handles the open state for you.

Manual popovers

Sometimes you do not want the browser to close the popover automatically.

Use:

<div id="notice" popover="manual">
  Important notice
</div>

A manual popover stays open until something closes it.

You can create separate show and hide buttons:

<button
  popovertarget="notice"
  popovertargetaction="show">
  Show notice
</button>

<button
  popovertarget="notice"
  popovertargetaction="hide">
  Hide notice
</button>

<div id="notice" popover="manual">
  Important notice
</div>

The popovertargetaction attribute can be:

show
hide
toggle

toggle is the default.

A small help box

The Popover API is also useful for extra information:

<p>
  Shutter count
  <button
    popovertarget="shutter-help"
    aria-label="What is shutter count?">
    ?
  </button>
</p>

<div id="shutter-help" popover>
  Shutter count is the number of mechanical shutter
  activations recorded by a camera.
</div>

A little CSS can make it feel like a normal info box:

#shutter-help {
  max-width: 20rem;
  padding: 1rem;

  border: 1px solid #ddd;
  border-radius: 0.5rem;

  line-height: 1.5;
}

Opening a popover from JavaScript

The good part about the Popover API is that you do not have to use JavaScript, but you still can when you need more control.

const popover = document.querySelector("#my-popover");

popover.showPopover();

To close it:

popover.hidePopover();

To toggle it:

popover.togglePopover();

This is still cleaner than building a custom popup system because the browser keeps the popover behaviour.

Listen for open and close changes

You can also listen for the toggle event:

const popover = document.querySelector("#my-popover");

popover.addEventListener("toggle", (event) => {
  console.log(event.newState);
});

This can be useful for analytics or when another part of the interface needs to react.

Popover or dialog?

A popover and a dialog are not the same thing.

I would use a popover for things like:

I would use <dialog> when the user needs to focus on a larger task, such as:

A popover is usually lighter and easier to dismiss.

Do not use popovers for everything

Just because a native popover is easy to build does not mean every small bit of text should become one.

If the content is important, it may be better to show it directly on the page.

A popover hides information until the user opens it. That can be useful, but it can also make a page harder to understand if overused.

Browser support

The Popover API reached Baseline 2025, which means it works in current versions of the main browsers.

If you support much older browser versions, check compatibility before using it for something critical.

For normal modern sites in 2026, it is a feature I would seriously consider.

A complete example

Here is a small account menu:

<button
  class="account-button"
  popovertarget="account-menu">
  My account
</button>

<div
  class="account-menu"
  id="account-menu"
  popover>

  <a href="/profile/">Profile</a>
  <a href="/settings/">Settings</a>
  <a href="/logout/">Log out</a>
</div>
.account-menu {
  min-width: 12rem;
  padding: 0.5rem;

  border: 1px solid #ddd;
  border-radius: 0.5rem;
  box-shadow: 0 0.5rem 2rem rgb(0 0 0 / 0.12);
}

.account-menu:popover-open {
  display: grid;
}

.account-menu a {
  padding: 0.6rem 0.75rem;
  text-decoration: none;
}

No event listeners are needed.

Why I like it

This is exactly the kind of feature I want from the web platform.

The browser already knows how to put something above other content. It already knows when Escape is pressed. It already knows when the user clicks outside an element.

I would rather let the browser handle those basic things than add the same JavaScript to every project.

The Popover API will not replace every custom menu or overlay, but for simple popovers it removes a lot of code.

And sometimes the best feature is the one that lets you delete JavaScript.