Popover

A floating content surface anchored to its trigger through the Popover API. It opens in the top layer, light-dismisses, and flips to stay inside the viewport, with an optional <header> region in plain semantic HTML. It ships no focus or keyboard behavior of its own; for a menu that needs those, see dropdown.

Examples

Default

Default popover surface with prose padding and shadow-lg elevation.

With header

Quick filters

Header takes the popover's full width via negative margins keyed to scoped padding.

Size

Small (14rem).

Default (20rem).

Large (32rem) for richer content.

no-border

Borderless surface carried by shadow alone; pair with a plain prose block or an image.

Basic usage

A floating surface anchored to its trigger. Click outside or press Escape to close.

<div>
                    <button
                        class="button"
                        type="button"
                        commandfor="pop-basic"
                        command="toggle-popover"
                    >
                        Open popover
                    </button>

                    <div class="popover" id="pop-basic" popover>
                        <p>
                            A floating surface anchored to its trigger. Click outside or press
                            Escape to close.
                        </p>
                    </div>
                </div>

Header (<header>)

Quick tips

The header's bottom border extends to the popover's edges by pulling through the surface padding.

<div>
                    <button
                        class="button"
                        type="button"
                        commandfor="pop-header"
                        command="toggle-popover"
                    >
                        Help
                    </button>

                    <div class="popover" id="pop-header" popover>
                        <header>
                            <h3>Quick tips</h3>
                            <button
                                class="dismiss"
                                type="button"
                                commandfor="pop-header"
                                command="hide-popover"
                                aria-label="Close"
                            >
                                &times;
                            </button>
                        </header>
                        <p>
                            The header's bottom border extends to the popover's edges by pulling
                            through the surface padding.
                        </p>
                    </div>
                </div>

Size

Compact bubble for short hints.

The default size accommodates a paragraph or two of explanatory content without feeling cramped.

A larger surface for content that needs more room -- a small form, a longer explanation, or a list of grouped options that wouldn't fit in the default size.

No max-width. Useful when the surface is meant to span much of the viewport, mega-menu style. Pair with composition primitives for internal layout.

<div class="cluster is-tight">
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-sm"
                        command="toggle-popover"
                    >
                        Small
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-default"
                        command="toggle-popover"
                    >
                        Default
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-lg"
                        command="toggle-popover"
                    >
                        Large
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-wide"
                        command="toggle-popover"
                    >
                        Wide
                    </button>

                    <div class="popover is-sm" id="pop-sm" popover>
                        <p>Compact bubble for short hints.</p>
                    </div>

                    <div class="popover" id="pop-default" popover>
                        <p>
                            The default size accommodates a paragraph or two of explanatory content
                            without feeling cramped.
                        </p>
                    </div>

                    <div class="popover is-lg" id="pop-lg" popover>
                        <p>
                            A larger surface for content that needs more room -- a small form, a
                            longer explanation, or a list of grouped options that wouldn't fit in
                            the default size.
                        </p>
                    </div>

                    <div class="popover is-wide" id="pop-wide" popover>
                        <p>
                            No max-width. Useful when the surface is meant to span much of the
                            viewport, mega-menu style. Pair with composition primitives for internal
                            layout.
                        </p>
                    </div>
                </div>

Placement

Default placement: below the trigger.

Above the trigger.

To the inline-start side of the trigger.

To the inline-end side of the trigger.

<div class="cluster is-tight">
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-bottom"
                        command="toggle-popover"
                    >
                        Below
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-top"
                        command="toggle-popover"
                    >
                        Above
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-start"
                        command="toggle-popover"
                    >
                        Start
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="pop-end"
                        command="toggle-popover"
                    >
                        End
                    </button>

                    <div class="popover" id="pop-bottom" popover>
                        <p>Default placement: below the trigger.</p>
                    </div>
                    <div class="popover is-top" id="pop-top" popover>
                        <p>Above the trigger.</p>
                    </div>
                    <div class="popover is-start" id="pop-start" popover>
                        <p>To the inline-start side of the trigger.</p>
                    </div>
                    <div class="popover is-end" id="pop-end" popover>
                        <p>To the inline-end side of the trigger.</p>
                    </div>
                </div>

Source comments

Popover -- floating content surface anchored to a trigger via the Popover API

Structure -- semantic HTML carries the regions, no slot classes:

  <button class="button" type="button"
          commandfor="my-popover" command="toggle-popover">Open</button>

  <div class="popover" id="my-popover" popover>
      <header>                    <-- optional first-child header slot;
          <h3>Title</h3>              full-bleed bordered separator
      </header>
      <p>Body content sits directly inside the popover.</p>
  </div>

Header slot (<header> as first child)

A <header> placed as the first child of the popover receives a
full-bleed bottom border treatment: negative inline margins equal to
the popover's inline padding pull the separator flush with the
popover's edges (P2 test 2). <header> at any other position stays at
UA defaults; the recipe is keyed to first-child only.

Heading level (h2-h6) is the author's choice per document hierarchy;
the header normalizes visual size via --font-size-base.

Toggle: native via commandfor + command="toggle-popover"
Close:  native via command="hide-popover" (from inside or outside the
        popover), or light dismiss (click outside / Escape)

Note: brio uses commandfor + command across every overlay (dialog,
popover, dropdown). The native popovertarget attribute also invokes
popovers, but combining popovertarget with command on the same trigger
fires two invocations per click and produces stuck-state bugs across
browsers. Pick one mechanism per trigger; brio picks commandfor.

Archetype: Overlay surface (P3). Generic floating surface; no companion
custom element. Focus management is the consumer's responsibility because
what to focus depends on the popover's content. For menu-shaped patterns
with focus + keyboard wiring, see dropdown.

Positioning: CSS anchor positioning. The Popover API provides an implicit
anchor (the trigger button that invoked the popover), so no anchor-name
declaration is required. position-try-fallbacks flips the panel on
overflow. Browsers without anchor positioning render the popover at the
browser-default top-layer position -- functional, just not anchored.

Animation: @starting-style + transition-behavior: allow-discrete on the
transform axis at top level. Opacity transition is fenced behind a non-
Safari @supports block to avoid a known class of Safari quirks where
opacity transitions on top-layer popovers produce visible jank. See the
dedicated comment block below for details.

No <footer> recipe (intentional divergence from dialog). A footer slot
would only earn P2 if a variant remapped it, and popover doesn't have
such variants. Consumers compose with .cluster, .stack, etc. when they
need footer-like trailing layouts.

Reference

Source: src/css/popover.css

Applies to

.popover

Classes

ClassKindDescription
.is-topvariantAnchored above the trigger
.is-startvariantAnchored to the inline-start side of the trigger
.is-endvariantAnchored to the inline-end side of the trigger
.is-smvariantNarrow popover at 14rem max width
.is-lgvariantWide popover at 32rem max width
.is-widevariantUncapped width
.no-borderopt-outRemoves the border

Slots

SlotDescription
> header:first-childHeader slot -- full-bleed bordered separator (P2 test 2: extends through parent's --popover-padding-inline via negative inline margins). Keyed to first-child so a <header> dropped mid-popover stays at UA defaults instead of breaking layout.

Tokens

TokenDefaultDescription
--popover-bgvar(--color-surface-float)Background color for the popover surface
--popover-colorvar(--color-text)Text color inside the popover
--popover-border-colorvar(--color-border)Border color for the popover surface
--popover-border-widthvar(--border-width-default)Border width for the popover surface
--popover-header-border-colorvar(--color-border)Separator border color below a first-child header
--popover-radiusvar(--radius-md)Border radius for the popover
--popover-padding-inlinevar(--ui-pad-inline-snug)Inline-axis padding inside the popover
--popover-padding-blockvar(--ui-pad-block-snug)Block-axis padding inside the popover
--popover-box-shadowvar(--shadow-lg)Box shadow for the popover
--popover-max-width20remMaximum width of the popover
--popover-offsetvar(--space-3xs)Gap between the trigger and the popover edge