Popover

A floating panel anchored to a trigger using the native popover API and CSS anchor positioning.

Works with

Button
The trigger that opens the popover

Standalone

<link rel="stylesheet" href="https://esm.sh/@erikt/ui/popover.css" />

Default

Connect a popovertarget button to a [popover] element by matching IDs. The button acts as the CSS anchor. No extra markup.

This is a popover.

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

<div id="my-popover" popover>Content</div>

With card

Use an <article class="card"> inside for structured content with header and footer sections.

Settings
<button popovertarget="my-popover">Options</button>

<div id="my-popover" popover>
  <article class="card">
    <header>Settings</header>
    <div style="display: grid; gap: 0.5rem">
      <label> <input type="checkbox" checked /> Notifications </label>
      <label> <input type="checkbox" /> Dark mode </label>
    </div>
    <footer>
      <button popovertarget="my-popover" popovertargetaction="hide">
        Close
      </button>
    </footer>
  </article>
</div>

With menu

Place a <menu> inside a [popover] to create a dropdown menu anchored to its trigger button. See the Menu page for more available variants.


  • <button popovertarget="my-popover">Options</button>
    
    <div id="my-popover" popover>
      <menu>
        <li><button class="ghost">Edit</button></li>
        <li><button class="ghost">Duplicate</button></li>
        <li><button class="ghost">Share</button></li>
        <li><hr /></li>
        <li><button class="ghost destructive">Delete</button></li>
      </menu>
    </div>

    Manual

    popover="manual" takes the popover out of the browser's auto stack. Three things change. Clicking outside it does nothing, Esc does nothing, and opening another popover no longer closes it. Something has to hide it on purpose, so give it a button with popovertargetaction="hide" or call hidePopover().

    Open both of these at once, then click the page around them. They stay put until you press Done.

    Filters
    Sort
    <button popovertarget="my-popover">Filters</button>
    
    <div id="my-popover" popover="manual">
      <article class="card">
        <header>Filters</header>
        <div style="display: grid; gap: 0.5rem">
          <label><input type="checkbox" checked /> Open</label>
          <label><input type="checkbox" /> Archived</label>
        </div>
        <footer>
          <button popovertarget="my-popover" popovertargetaction="hide">
            Done
          </button>
        </footer>
      </article>
    </div>

    Placement

    Use data-placement on the [popover] element to control which side it appears on and which edges align. The value is two space-separated words: side and alignment. Without data-placement, the popover appears below the trigger with automatic viewport fallbacks.

    bottom left

    Appears below the trigger, left edges aligned.

    bottom right

    Appears below the trigger, right edges aligned.

    top left

    Appears above the trigger, left edges aligned.

    top right

    Appears above the trigger, right edges aligned.

    left top

    Appears left of the trigger, top edges aligned.

    left bottom

    Appears left of the trigger, bottom edges aligned.

    right top

    Appears right of the trigger, top edges aligned.

    right bottom

    Appears right of the trigger, bottom edges aligned.

    <button popovertarget="my-popover">Open</button>
    
    <div id="my-popover" popover data-placement="right top">Content</div>

    API reference

    Type Classes / attributes What it does
    Placement [data-placement="bottom left"]
    [data-placement="bottom right"]
    [data-placement="top left"]
    [data-placement="top right"]
    [data-placement="left top"]
    [data-placement="left bottom"]
    [data-placement="right top"]
    [data-placement="right bottom"]
    Sets which side of the trigger the popover opens on

    Search 5021 icons

    Type a name to find icons from the Tabler icon set.

        Move Open Esc Close