Anchor Popover Menu
A dropdown menu with zero JavaScript — the native HTML Popover API (popovertarget/popover) paired with CSS anchor positioning (anchor-name/position-anchor/anchor()) for placement, plus @starting-style + transition-behavior: allow-discrete for a real open/close fade-and-scale animation on an element that toggles display: none. This is the exact problem Floating UI, Popper.js, and headless-UI dropdown components exist to solve, now handled by the browser. **Accuracy update (2026-09-28, this catalog's own drift check):** when this entry was written, anchor positioning was described as 'not fully Baseline yet, Firefox 147+' as a forward-looking target. That target has since actually shipped and been reached: multiple independent sources (Refonte Learning's 'CSS Anchor Positioning Reaches Baseline in 2026', web-platform-dx/web-features issue #3558, and OddBird's ongoing anchor-positioning coverage) agree Firefox 147 unflagged the feature in mid-January 2026, which per the Baseline process automatically promoted core anchor positioning to Baseline 'Newly available' across Chrome/Edge 125+, Safari 26+, and Firefox 147+ — so as of this run it genuinely is Baseline, not merely targeting it. This is not being rounded up to 'flawless': OddBird's own tracking (oddbird.net, Fall 2025 into 2026) documents real, still-open cross-engine quirks in the newer sub-parts of the spec (position-visibility, anchor-size(), and a Safari containing-block quirk where an anchored element can be partially covered by its anchor) — the umbrella feature reached Baseline, but its edges are still shaking out. **Second accuracy update (2026-10-23, this catalog's own drift check — a real bug, now fixed, not just reworded):** the fallback claim directly above this line used to read that the non-anchor path 'falls back to a plain position: absolute dropdown' which 'remains correct defensive code.' This catalog's own later 'Anchor-Size Matched Select' entry (built 2026-10-20) found, via a real headless-Chromium bounding-box measurement, that `position:absolute` on a `popover`-attribute element does not resolve against a `position:relative` wrapper the normal way: once `showPopover()` promotes the element into the top layer, its containing block becomes the initial containing block (the viewport), not its nearest positioned ancestor. Re-run against this entry's own exact markup this run, same method (open the popover, measure both elements' real rendered bounding boxes in an isolated 1280×720 headless-Chromium page, button offset from the viewport origin so the two can't be confused): confirmed the bug reproduces here too, and precisely — not merely 'in a corner' as a first-pass description of this class of bug might round it to. The old fallback's `position:absolute;top:calc(100% + 8px);left:0` resolved against the viewport (per the top-layer containing-block quirk above) as `x:0, y:728` on a 720px-tall viewport — meaning the menu's top edge started 8px *below the bottom edge of the viewport itself*: fully off-screen, invisible, not just mis-positioned, on any engine without anchor-positioning support. **Fixed in the code this run, not just in prose:** the unsupported-browser path no longer tries to fake a position-under-trigger placement without the real primitive; it now leaves the Popover API's own UA-default centered top-layer placement (`position:fixed;inset:0;margin:auto;width/height:fit-content`) in effect — which required moving this rule's own `margin:0` *into* the `@supports` block rather than just deleting the `position`/`top`/`left` overrides, since an unconditional `margin:0` on the base rule silently defeats the UA stylesheet's own `margin:auto` centering (caught by this run's own first attempt at the fix rendering at `x:0,y:0` instead of centered — a second real bug this run found in its own draft before shipping, not assumed correct from reading the CSS alone). This is the same honest fallback shape 'Anchor-Size Matched Select' already uses, and now matches that entry's own `margin:0`-inside-`@supports` placement exactly. Re-verified this run, same bounding-box method: with the @supports (anchor-name: --a) block disabled to simulate an unsupporting engine, the menu now renders at `x:541,y:297` on the same 1280×720 viewport — its center within 1px of the viewport's true center on both axes — genuinely centered, not off-screen. (Vanilla example: live iframe preview + HTML/CSS tabs — click the button.)
<div class="apm-wrap">
<button class="apm-btn" popovertarget="apm-menu">Options ▾</button>
<div id="apm-menu" class="apm-menu" popover>
<a href="#" class="apm-item">Dashboard</a>
<a href="#" class="apm-item">Settings</a>
<a href="#" class="apm-item">Sign out</a>
</div>
</div>How it works
Anchor Popover Menu is a hand-built button component in plain HTML and CSS — no React, no Tailwind, no framework at all. Paste it into any site as-is and it stays performant on real devices. It's free — copy the code above and ship it.
← Browse all components