unscripted/ui

Dropdown Menu

Top-layer rendering, Esc + click-outside dismiss, anchored under the trigger, auto-flips at viewport edges. All attributes and CSS.

popoveranchor positioningexit animations

How it works

  • The popover attribute + popovertarget on the button gives top-layer rendering, toggling, Esc and click-outside dismiss.
  • CSS anchor positioning pins the panel under the trigger: [anchor-name:--dd-options] on the button, then [position-anchor:--dd-options] + [position-area:block-end_span-inline-end] on the panel (“below the anchor, growing to the right”).
  • [position-try-fallbacks:flip-block] flips the panel above the trigger near the bottom of the viewport.
  • position-area is unknown to browsers without anchor support, so they ignore it and the menu opens centered instead (the top-layer default). That’s why the base classes keep m-auto. Only the margin reset (m-0 plus the mt-1.5 gap) and the transform origin need explicit supports-[anchor-name:--a]: guards.
  • One trap this dodges: resetting placement with the inset shorthand under a variant can land later in the stylesheet than your top/left longhands and silently wipe them. position-area doesn’t touch insets at all.

Accessibility

Focus moves into the menu with Tab; Esc returns to the trigger. This is a popover, not an ARIA menu. There’s no roving arrow-key navigation. For most “actions under a button” cases that’s fine; if you need full menu semantics, that genuinely still needs JavaScript.

Browser support

Minimum stable version per engine, resolved at build time from MDN's browser-compat-data; Baseline status from the official web-features dataset. Everything degrades gracefully — the “when missing” column is the actual behavior, not a broken page.

FeatureChromeEdgeFirefoxSafariWhen missing
Popover APIBaseline 2025 · newly available11411412517Content renders in normal document flow, always visible, and the trigger does nothing.
CSS anchor positioningLimited availability12912914726The popover opens centered in the viewport (the top-layer default) instead of attached to its trigger.
Entry/exit animations (allow-discrete + @starting-style)Baseline 2024 · newly available11711712917.5Elements appear and disappear instantly. Nothing breaks — you just lose the animation.

† @supports cannot test at-rules, so the badge checks transition-behavior: allow-discrete, which co-shipped with @starting-style in every engine.