MenuChevron Down
Popover - Docs - Artefact

Popover

Overlays
Auto-interactive

Introduction

An interactive element that displays additional content in a layer over its anchor.

Usage

import { Popover } from "../components/ui/popover";
import { Button } from "../components/ui/button";

<Popover
  placement="right"
  trigger={<Button>Open Popover</Button>}
  title="Title"
  description="Description"
  body="Popover Body"
/>;

CMS Page Builder

This component is available as a popover block in the Page Builder (content/pages/*.json):

{
  "type": "popover",
  "triggerText": "Open Popover",
  "title": "Title",
  "description": "Description",
  "body": "Popover Body"
}

Props

Root

PropTypeDescription
childrenanyPopover sub-components.
openbooleanWhether the popover is open (controlled).
defaultOpenbooleanInitial open state (uncontrolled). Default false.
onOpenChange(details: { open: boolean }) => voidCalled when the popover opens or closes.

| placement | `"top" \ | "bottom" \ | "left" \ | "right"` | Which side of the trigger the content opens on. Default "bottom". Flips to the opposite side automatically if there isn't enough viewport room. |

| interactive | boolean | Forces hydration as an island. Defaults to true. | | id | string | Unique identifier for the popover. | | closeOnEscape | boolean | Close when Escape is pressed. Default true. | | closeOnInteractOutside | boolean | Close on pointer interaction outside, or when focus tabs away from the popover. Default true. | | onClose | () => void | Callback triggered when the popover closes. | | onToggle | () => void | Callback triggered when the popover toggles. |

Trigger

PropTypeDescription
asChildbooleanWhether to merge props onto the immediate child element.

Limitations

The interactive island positions and sizes the popover relative to its trigger: it flips to the opposite side (e.g. bottomtop) when the requested placement would overflow the viewport, and clamps the cross axis so the content never renders off-screen. It does not track scroll containers or resize observers the way Floating UI does — repositioning only re-runs on window resize while the popover is open, and (since the positioner is anchored via position: absolute to the trigger's own wrapper) scrolling the page moves it along with the trigger for free.

Nesting one Popover's trigger inside another Popover's content is supported (click delegation is scoped per popover instance), but nesting a Popover inside a Tooltip's trigger, or vice versa, is not — the two components don't coordinate data-part ownership across component types.

The _closed exit animation (scale-fade-out) plays before the popover is actually removed from layout — closing doesn't hide it instantly.