Repo

The trigger needs anchor-name set to match the popover's id (prefixed with --). The Astro and React wrappers set position-anchor automatically from the id prop.

Usage

Popover content goes here.

<button
class="zui-button"
popovertarget="demo-popover"
style="anchor-name: --demo-popover"
>
Open popover
</button>
<div id="demo-popover" popover class="zui-popover" style="position-anchor: --demo-popover;">
<p>Popover content goes here.</p>
</div>

Auto vs manual

popover="auto" (default) closes when clicking outside or pressing Esc. popover="manual" requires an explicit close trigger.

I close when you click outside.

I stay open until explicitly closed.

<button class="zui-button" popovertarget="pop-auto" style="anchor-name: --pop-auto">
Auto (click outside to close)
</button>
<div id="pop-auto" popover="auto" class="zui-popover" style="position-anchor: --pop-auto;">
<p>I close when you click outside.</p>
</div>

<button class="zui-button zui-button-variant-outline" popovertarget="pop-manual" style="anchor-name: --pop-manual">
Manual (must use close button)
</button>
<div id="pop-manual" popover="manual" class="zui-popover" style="position-anchor: --pop-manual;">
<p>I stay open until explicitly closed.</p>
<button class="zui-button zui-button-size-sm" style="margin-top:0.5rem;" popovertarget="pop-manual" popovertargetaction="hide">
  Close
</button>
</div>

With rich content

<button class="zui-button" popovertarget="pop-rich" style="anchor-name: --pop-rich">
Options
</button>
<div id="pop-rich" popover class="zui-popover" style="position-anchor: --pop-rich; min-width:14rem;">
<div style="display:flex;flex-direction:column;gap:0.25rem;">
  <button class="zui-button zui-button-variant-ghost" style="justify-content:flex-start;">
    <i class="ph ph-pencil"></i> Edit
  </button>
  <button class="zui-button zui-button-variant-ghost" style="justify-content:flex-start;">
    <i class="ph ph-copy"></i> Duplicate
  </button>
  <button class="zui-button zui-button-variant-ghost zui-button-color-destructive" style="justify-content:flex-start;">
    <i class="ph ph-trash"></i> Delete
  </button>
</div>
</div>

Shape

Use the shape prop to change the corners: default (rounded), hard (square) or squircle (a rounded square with smooth corners). Browsers without corner-shape support show normal rounded corners for squircle.

This popover uses the default shape.

This popover uses the hard shape.

This popover uses the squircle shape.

<button
class="zui-button"
popovertarget="sq-popover"
style="anchor-name: --sq-popover"
>
Open popover
</button>
<div id="sq-popover" popover class="zui-popover zui-popover-shape-squircle" style="position-anchor: --sq-popover;">
<p>Popover content goes here.</p>
</div>

To make squircle the default everywhere, add zui-squircle-all to <html> — see Squircle.

Browser support

The popover uses the Popover API and CSS anchor positioning. The Popover API works in all current browsers. Anchor positioning needs Chrome or Edge 125, Safari 26 or Firefox 147 or later.

In older browsers, the popover shows in the centre of the viewport, not next to its trigger. To get the correct position in these browsers, load the CSS anchor positioning polyfill in your app.

CSS custom properties

Set these on :root, on a wrapper, or on the element. See Component custom properties.

Property Default Description
--zui-popover-bg var(--color-surface) Background colour
--zui-popover-fg currentColor Text colour
--zui-popover-border var(--color-border) Border colour
--zui-popover-border-width 1px Border width. Set to 0 to hide
--zui-popover-border-style var(--border-style, solid) Border style (solid, dashed, dotted, …)
--zui-popover-radius var(--radius-lg) Border radius
--zui-popover-shadow var(--shadow-lg) Box shadow
--zui-popover-padding var(--space-xs) Padding inside the popover
--zui-popover-min-width 12rem Minimum width

Theme

Copy this CSS to your project: