HTML Popover Table

PieceWhat it doesField note
popover attributeThe whole widgetOne attribute = top layer + light dismiss + a11y wiring
popovertarget on buttonThe triggerDeclarative open/close - zero JS for the basic popover
popover=auto vs manualDismissal semanticsauto: light-dismiss + only one open; manual: neither
::backdropThe dim layerStyle the page behind - top layer beats every z-index
popovertargetaction=show/hideSplit buttonsSeparate open and close triggers - menu-bar pattern
beforetoggle / toggleThe eventsPrevent beforetoggle to veto; toggle to lazy-render
top layerThe superpowerNo z-index war with parents - overflow and transforms stop mattering
vs <dialog>Modal vs popoverdialog showModal: modal + focus trap; popover: non-modal light-dismiss
Reference: the MDN Popover API reference. The popover attribute compresses a whole widget into markup: popover on the element, popovertarget on a button, and you get TOP LAYER rendering (no z-index war - parents with transforms and overflow cannot trap it), light dismissal, focus handling and screen-reader semantics with zero JavaScript. Bottom line: popover=auto gives light-dismiss and single-open (menus, tooltips); popover=manual is sticky (toasts, teaching UI); the toggle event enables lazy rendering; and the dialog-vs-popover split is modal-with-focus-trap versus non-modal-light-dismiss. Pair with anchor positioning for placement. Related tools: anchor positioning table (the placement half), details table (the inline disclosure sibling), and WAI-ARIA table (the semantics it wires for you).

The popover attribute compresses a whole widget into markup: popover on the element, popovertarget on a button - and you get TOP LAYER rendering (no z-index war: parents with transforms and overflow cannot trap it), light dismissal, focus handling and screen-reader semantics with zero JavaScript.

Bottom line: popover=auto gives light dismissal and single-open enforcement (menus, tooltips, pickers); popover=manual is sticky and stackable (toasts, teaching UI). The toggle event enables lazy rendering, beforetoggle can veto, and placement comes from the anchor positioning pair.

The honest part: the dialog-versus-popover split is modal versus non-modal - dialog's showModal() takes focus, blocks the page and needs explicit close; popover is ambient (light-dismiss, no focus grab). Menus and toasts are popovers; confirmations and wizards are dialogs. Picking wrong is a UX bug, not a technical one.

How to use

  1. Ship the menu in three lines: <button popovertarget=menu>Open</button> <div id=menu popover=auto>items</div> - declarative open, click-away close, focus handled.
  2. Render lazily: menu.addEventListener('toggle', e => { if (e.newState === 'open' && !filled) fillMenu(); }) - first open pays the render, page load does not.
  3. Split the triggers: popovertargetaction=show on the open button, =hide on the close button inside - the menu-bar pattern without JS wiring.

Frequently asked questions

What does the top layer actually solve?

The stacking-context prison. A dropdown inside a card with transform: translate or overflow: hidden gets clipped or buried - z-index fights parents because z-index is relative to the stacking context, and the parent's context wins. Top-layer elements (popovers, modal dialogs) render OUTSIDE every stacking context: no parent transform, overflow or z-index can clip or bury them, and ::backdrop dims the entire page behind. This is why popover-based menus work inside any markup no matter how hostile the ancestor CSS - the class of 'my dropdown is cut off' bugs ceases to exist rather than getting patched.

What is the real difference between popover=auto and popover=manual?

Dismissal philosophy. auto is a transient surface: clicking outside closes it (light dismiss), pressing Esc closes it, and OPENING one auto popover closes other open ones (single-open enforcement - the menu behavior). manual is a sticky surface: no light dismiss, multiple can stack (toast stacks, onboarding callouts that must not vanish on stray clicks). Picking wrong cuts both ways: auto on a toast means it evaporates on any outside click; manual on a menu means users must find the close button. There is also the hybrid pattern - auto popover containing a manual popover - for nested UI like a menu with a pinned submenu.

When is a popover the wrong element versus dialog?

Modal versus non-modal is the split. dialog showModal() grabs focus, traps it (Tab cycles inside), blocks page interaction and demands an explicit dismissal - the contract for confirmations, forms and wizards where the user MUST decide before proceeding. Popover is ambient: no focus grab, page stays interactive, light dismiss - the contract for supplementary UI (menus, pickers, hints). Using dialog for a menu traps keyboard users out of the page; using popover for a confirmation lets users dismiss it accidentally and lose the decision. The one-line test: should the user be able to ignore this and keep working? Ignore-able = popover; must-answer = dialog.

How do the beforetoggle and toggle events drive real popover behavior?

beforetoggle is the veto and prepare point: calling preventDefault() cancels the open (guard rails - 'cannot open while saving'), and it can prepare state before showing. toggle fires after the state change (e.newState: 'open'/'closed') and is the lazy-render hook - filling expensive content on first open instead of page load, exactly like details' toggle. The pair also powers cleanup: on closed, return focus or reset internal state. One caveat: the events fire for BOTH directions, so handlers must branch on newState rather than assuming opens - the same both-directions discipline as matchMedia's change event.

Related tools