Add this component

npx zentauri-ui add popover

Accessibility notes

Overlay patterns include focus, dismissal, and semantic roles where the component owns interaction. Verify trigger labels and escape behavior in your flow.

Dependency notes

Static imports do not pull framer-motion. Use the animated entry only when you want motion and have framer-motion installed.

Overlay

Popovers for interactive floating content

Popovers open from a trigger and hold interactive content such as short forms, status details, and compact action panels. Use them when a tooltip is too passive and a modal is too heavy.

Interactive popover examples

Popovers are for focusable content: quick edits, notification previews, and dense status panels that need click or keyboard interaction.



Popover variants playground

Pick an appearance, size, width, side, and align to preview the popover live. Toggle Show output / Show code and the snippet updates to match the selected variant.

For mobile viewport, all the popovers are top and start aligned so they won’t overflow outside the screen


Animated popover

The animated entry renders PopoverContentAnimated with a motion preset. Pick a preset to preview it live.


Popover API

Generated from the package prop types and variant definitions.

Popover

PopoverProps

State

PropTypeDefault
defaultOpenboolean | undefinednone
onOpenChange((open: boolean) => void) | undefinednone
openboolean | undefinednone

Behavior

PropTypeDefault
closeOnEscapeboolean | undefinednone
closeOnOutsideClickboolean | undefinednone

Content

PropTypeDefault
children*ReactNodenone

PopoverContent

PopoverContentProps

Variants

PropTypeDefault
size
lgmdsm
md
variant
aquabluecrimsoncyandefaultelectricemeraldforestghostglassgradient-bluegradient-green+31
default
width
2xllgmdsmxlxs
xs

Behavior

PropTypeDefault
alignPopoverAlign | undefinednone
sidePopoverSide | undefinednone

Content

PropTypeDefault
childrenReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

PopoverTrigger

PopoverTriggerProps

Content

PropTypeDefault
children*ReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone

PopoverContentAnimated

PopoverContentAnimatedProps

animated

Behavior

PropTypeDefault
alignPopoverAlign | undefinednone
animationPopoverAnimation | undefinednone
sidePopoverSide | undefinednone
size'md' | 'sm' | 'lg' | null | undefinednone
variant'default' | 'outline' | 'ghost' | 'blue' | 'cyan' | 'green' | 'lime' | 'mint' | 'ocean' | 'sapphire' | 'lavender' | 'ruby' | 'red' | 'slate' | 'zinc' | 'stone' | 'royal' | 'electric' | 'forest' | 'sunset' | 'magenta' | 'crimson' | 'aqua' | 'plum' | 'sky' | 'rose' | 'purple' | 'pink' | 'orange' | 'yellow' | 'teal' | 'indigo' | 'emerald' | 'gradient-blue' | 'gradient-green' | 'gradient-red' | 'gradient-yellow' | 'gradient-purple' | 'gradient-teal' | 'gradient-indigo' | 'gradient-pink' | 'gradient-orange' | 'glass' | null | undefinednone
width'md' | 'sm' | 'lg' | 'xl' | '2xl' | 'xs' | null | undefinednone

Content

PropTypeDefault
childrenReactNodenone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone
CSS variable overrides

Popover CSS variables

Override these popover variables on :root, a theme selector, or a component wrapper.

256 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-popover-default-border: oklch(20.8% 0.042 265.755 / 0.1);
  --zui-popover-default-bg: #ffffff;
  --zui-popover-default-fg: oklch(20.8% 0.042 265.755);
  --zui-popover-outline-border: oklch(37.3% 0.034 259.733);
  --zui-popover-outline-bg: #ffffff;
  --zui-popover-outline-fg: oklch(21% 0.034 264.665);
  --zui-popover-ghost-bg: oklch(96.7% 0.003 264.542);
  --zui-popover-ghost-fg: oklch(21% 0.034 264.665);
  --zui-popover-glass-border: #00000026;
  --zui-popover-glass-bg: #ffffffb3;
  --zui-popover-glass-fg: oklch(20.8% 0.042 265.755);
  --zui-popover-emerald-border: oklch(43.2% 0.095 166.913 / 0.35);
  --zui-popover-emerald-bg: oklch(90.5% 0.093 164.15);
  --zui-popover-emerald-fg: oklch(37.8% 0.077 168.94);
  --zui-popover-indigo-border: oklch(39.8% 0.195 277.366 / 0.35);
  --zui-popover-indigo-bg: oklch(87% 0.065 274.039);
  --zui-popover-indigo-fg: oklch(35.9% 0.144 278.697);
  --zui-popover-purple-border: oklch(43.8% 0.218 303.724 / 0.35);
  --zui-popover-purple-bg: oklch(90.2% 0.063 306.703);
  --zui-popover-purple-fg: oklch(38.1% 0.176 304.987);
  --zui-popover-pink-border: oklch(45.9% 0.187 3.815 / 0.35);
  --zui-popover-pink-bg: oklch(89.9% 0.061 343.231);
  --zui-popover-pink-fg: oklch(40.8% 0.153 2.432);
  --zui-popover-rose-border: oklch(45.5% 0.188 13.697 / 0.35);
  --zui-popover-rose-bg: oklch(89.2% 0.058 10.001);
  --zui-popover-rose-fg: oklch(41% 0.159 10.272);
  --zui-popover-sky-border: oklch(44.3% 0.11 240.79 / 0.35);
  --zui-popover-sky-bg: oklch(90.1% 0.058 230.902);
  --zui-popover-sky-fg: oklch(39.1% 0.09 240.876);
  --zui-popover-teal-border: oklch(43.7% 0.078 188.216 / 0.35);
  --zui-popover-teal-bg: oklch(91% 0.096 180.426);
  --zui-popover-teal-fg: oklch(38.6% 0.063 188.416);
  --zui-popover-yellow-border: oklch(47.6% 0.114 61.907 / 0.35);
  --zui-popover-yellow-bg: oklch(94.5% 0.129 101.54);
  --zui-popover-yellow-fg: oklch(42.1% 0.095 57.708);
  --zui-popover-orange-border: oklch(47% 0.157 37.304 / 0.35);
  --zui-popover-orange-bg: oklch(90.1% 0.076 70.697);
  --zui-popover-orange-fg: oklch(40.8% 0.123 38.172);
  --zui-popover-green-border: oklch(44.8% 0.119 151.328 / 0.35);
  --zui-popover-green-bg: oklch(92.5% 0.084 155.995);
  --zui-popover-green-fg: oklch(39.3% 0.095 152.535);
  --zui-popover-gradient-blue-from: oklch(42.4% 0.199 265.638);
  --zui-popover-gradient-blue-to: oklch(43.8% 0.218 303.724);
  --zui-popover-gradient-blue-fg: #ffffff;
  --zui-popover-gradient-green-from: oklch(44.8% 0.119 151.328);
  --zui-popover-gradient-green-to: oklch(45.3% 0.124 130.933);
  --zui-popover-gradient-green-fg: #ffffff;
  --zui-popover-gradient-red-from: oklch(44.4% 0.177 26.899);
  --zui-popover-gradient-red-to: oklch(45.9% 0.187 3.815);
  --zui-popover-gradient-red-fg: #ffffff;
  --zui-popover-gradient-yellow-from: oklch(47.6% 0.114 61.907);
  --zui-popover-gradient-yellow-to: oklch(47% 0.157 37.304);
  --zui-popover-gradient-yellow-fg: #ffffff;
  --zui-popover-gradient-purple-from: oklch(43.8% 0.218 303.724);
  --zui-popover-gradient-purple-to: oklch(45.9% 0.187 3.815);
  --zui-popover-gradient-purple-fg: #ffffff;
  --zui-popover-gradient-teal-from: oklch(43.7% 0.078 188.216);
  --zui-popover-gradient-teal-to: oklch(45% 0.085 224.283);
  --zui-popover-gradient-teal-fg: #ffffff;
  --zui-popover-gradient-indigo-from: oklch(39.8% 0.195 277.366);
  --zui-popover-gradient-indigo-to: oklch(43.8% 0.218 303.724);
  --zui-popover-gradient-indigo-fg: #ffffff;
  --zui-popover-gradient-pink-from: oklch(45.9% 0.187 3.815);
  --zui-popover-gradient-pink-to: oklch(45.5% 0.188 13.697);
  --zui-popover-gradient-pink-fg: #ffffff;
  --zui-popover-gradient-orange-from: oklch(47% 0.157 37.304);
  --zui-popover-gradient-orange-to: oklch(44.4% 0.177 26.899);
  --zui-popover-gradient-orange-fg: #ffffff;
  --zui-popover-content-blue-border: #2563eb;
  --zui-popover-content-blue-bg: #2563eb14;
  --zui-popover-content-blue-fg: #0f172a;
  --zui-popover-content-cyan-border: #0891b2;
  --zui-popover-content-cyan-bg: #0891b214;
  --zui-popover-content-cyan-fg: #0f172a;
  --zui-popover-content-lime-border: #65a30d;
  --zui-popover-content-lime-bg: #65a30d14;
  --zui-popover-content-lime-fg: #0f172a;
  --zui-popover-content-mint-border: #10b981;
  --zui-popover-content-mint-bg: #10b98114;
  --zui-popover-content-mint-fg: #0f172a;
  --zui-popover-content-ocean-border: #0284c7;
  --zui-popover-content-ocean-bg: #0284c714;
  --zui-popover-content-ocean-fg: #0f172a;
  --zui-popover-content-sapphire-border: #1d4ed8;
  --zui-popover-content-sapphire-bg: #1d4ed814;
  --zui-popover-content-sapphire-fg: #0f172a;
  --zui-popover-content-lavender-border: #8b5cf6;
  --zui-popover-content-lavender-bg: #8b5cf614;
  --zui-popover-content-lavender-fg: #0f172a;
  --zui-popover-content-ruby-border: #be123c;
  --zui-popover-content-ruby-bg: #be123c14;
  --zui-popover-content-ruby-fg: #0f172a;
  --zui-popover-content-red-border: #dc2626;
  --zui-popover-content-red-bg: #dc262614;
  --zui-popover-content-red-fg: #0f172a;
  --zui-popover-content-slate-border: #475569;
  --zui-popover-content-slate-bg: #47556914;
  --zui-popover-content-slate-fg: #0f172a;
  --zui-popover-content-zinc-border: #52525b;
  --zui-popover-content-zinc-bg: #52525b14;
  --zui-popover-content-zinc-fg: #0f172a;
  --zui-popover-content-stone-border: #57534e;
  --zui-popover-content-stone-bg: #57534e14;
  --zui-popover-content-stone-fg: #0f172a;
  --zui-popover-content-royal-border: #4338ca;
  --zui-popover-content-royal-bg: #4338ca14;
  --zui-popover-content-royal-fg: #0f172a;
  --zui-popover-content-electric-border: #0ea5e9;
  --zui-popover-content-electric-bg: #0ea5e914;
  --zui-popover-content-electric-fg: #0f172a;
  --zui-popover-content-forest-border: #166534;
  --zui-popover-content-forest-bg: #16653414;
  --zui-popover-content-forest-fg: #0f172a;
  --zui-popover-content-sunset-border: #ea580c;
  --zui-popover-content-sunset-bg: #ea580c14;
  --zui-popover-content-sunset-fg: #0f172a;
  --zui-popover-content-magenta-border: #c026d3;
  --zui-popover-content-magenta-bg: #c026d314;
  --zui-popover-content-magenta-fg: #0f172a;
  --zui-popover-content-crimson-border: #b91c1c;
  --zui-popover-content-crimson-bg: #b91c1c14;
  --zui-popover-content-crimson-fg: #0f172a;
  --zui-popover-content-aqua-border: #0f766e;
  --zui-popover-content-aqua-bg: #0f766e14;
  --zui-popover-content-aqua-fg: #0f172a;
  --zui-popover-content-plum-border: #7e22ce;
  --zui-popover-content-plum-bg: #7e22ce14;
  --zui-popover-content-plum-fg: #0f172a;
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-popover-default-border-dark: #ffffff1a;
  --zui-popover-default-bg-dark: oklch(20.8% 0.042 265.755);
}

What it does

Popover provides click-triggered floating content that can contain buttons, inputs, links, and compact workflows.

It closes on outside click and Escape by default, while supporting controlled state for application-managed overlays.

Composition and API

Use Popover, PopoverTrigger, and PopoverContent as compound parts. Content controls side, align, width, size, and variant independently from the trigger.

Common use cases

  • Open quick-edit forms from dense tables.
  • Show notification summaries without leaving the current page.
  • Collect a small amount of metadata near the related control.
  • Expose secondary actions while preserving the current workflow.

Accessibility

The trigger exposes expanded state and controls the dialog content. Keep labels visible, preserve focus rings, and test keyboard-only flows when content contains form controls.

Next.js integration notes

Keep Popover usage in client components. Static page copy and SEO can remain server-rendered, while the interactive preview islands import the popover primitives.

FAQ

When should I use Popover instead of Tooltip?

Use Tooltip for short, non-interactive hints. Use Popover when the content needs focusable controls, links, forms, or click-driven disclosure.

Does the Popover component work with Next.js App Router?

Yes. Popover is a client component because it manages open state, outside clicks, and keyboard dismissal. Import it inside client boundaries where the trigger is interactive.

Can I theme Popover with CSS variables?

Yes. Popover follows the Zentauri UI token pattern with --zui-popover-* variables for content surfaces, brand appearances, and gradients.