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.
<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.
<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.
Appears below the trigger, left edges aligned.
Appears below the trigger, right edges aligned.
Appears above the trigger, left edges aligned.
Appears above the trigger, right edges aligned.
Appears left of the trigger, top edges aligned.
Appears left of the trigger, bottom edges aligned.
Appears right of the trigger, top edges aligned.
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 |