popover
Anchor-positioned popover on the native Popover API — behaviour and placement without JavaScript.
All behaviour is native. Every trigger below is a
plain <button popovertarget="…"> — the browser
toggles the popover, renders it in the top layer and (for the
default popover="auto") closes it on an outside click
or Esc. The placement next to the trigger is pure CSS:
CSS anchor positioning, explained
below the examples.
✔ This browser supports CSS anchor positioning — the popovers on this page are placed by the stylesheet alone; the component's JavaScript does nothing but validate the markup.
✖ This browser does not support CSS anchor positioning yet — the component's JavaScript fallback is anchoring the popovers instead (measured per frame, same sides, same flip behaviour).
Default (light dismiss, placed below)
A default popover="auto": click outside it or press
Esc and it closes itself — no close button required.
It sits below its trigger because bottom is the
default placement.
Placement (data-popover-position)
position-area: top — centered above the trigger.
position-area: right — centered right of the trigger.
position-area: bottom — the default.
position-area: left — centered left of the trigger.
Anchored, not parked — scroll while it is open
The popover is tethered to its anchor, not to a coordinate: open
it, then scroll the page. It follows the trigger,
and when the space below runs out it flips above it
(position-try-fallbacks: flip-block) — the browser
re-evaluates the placement continuously.
Keep scrolling — I stay glued to my trigger and flip to its other side at the viewport edge.
Manual (popover="manual")
A manual popover has no light dismiss — outside clicks and
Esc are ignored, so it must keep a visible close
control. The × button closes it natively via
popovertargetaction="hide"; several manual popovers
can even be open at once.
Pinned note
I stay open while you click around the page — only the × (or my trigger) closes me.
CSS anchor positioning in a nutshell
A top-layer overlay is a position: fixed box that
knows nothing about its trigger — placing it next to one used to
mean JavaScript (or a library like Floating UI). Anchor
positioning (Chrome/Edge 125+, Safari 26+, Firefox in development)
moves that into CSS:
.trigger { anchor-name: --my-anchor; }
.overlay {
position: fixed;
position-anchor: --my-anchor;
inset: auto; /* undo the UA centering of [popover] */
position-area: bottom; /* below the anchor, centered */
position-try-fallbacks: flip-block;
}
-
Implicit anchor: this component ships no
anchor-nameat all — a popover opened viapopovertargetautomatically gets that button as its anchor. -
position-areaplaces the overlay on a 3×3 grid around the anchor (top,bottom span-right,block-end, …); naming only one axis centers it on the other. For fine-grained control there are alsotop: anchor(bottom)andanchor-size(). -
position-try-fallbackskeeps the overlay on screen: the placement is re-evaluated on every scroll and resize, flipping to the opposite side when space runs out — see the “scroll while it is open” example above. -
No support? Detected with the same
@supportscondition in CSS and JS: popover.js then measures the trigger itself and feeds--popover-fallback-*custom properties to the stylesheet; without JS the UA default (centered in the viewport) still works.