Popover
Floating content anchored to a trigger element. Non-modal by default — clicks outside dismiss it. Use for inline forms, info, or quick actions.
Inline form
Info card
Right-anchored
Installation
pnpm dlx @hex-core/cli add popoverInline form
Compact form anchored to a button — labelled inputs and a Save action stay inside the popover surface
function GoalPopover() {
const [target, setTarget] = useState("");
const [deadline, setDeadline] = useState("");
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Set goal</Button>
</PopoverTrigger>
<PopoverContent className="w-72">
<form
className="space-y-3"
onSubmit={(event) => {
event.preventDefault();
saveGoal({ target, deadline });
}}
>
<div className="grid gap-1.5">
<Label htmlFor="target">Target</Label>
<Input
id="target"
type="number"
min={0}
value={target}
onChange={(e) => setTarget(e.target.value)}
/>
</div>
<div className="grid gap-1.5">
<Label htmlFor="deadline">Deadline</Label>
<Input
id="deadline"
type="date"
value={deadline}
onChange={(e) => setDeadline(e.target.value)}
/>
</div>
<Button type="submit" className="w-full">Save goal</Button>
</form>
</PopoverContent>
</Popover>
);
}Decoupled trigger and anchor
Anchor the popover to a different element than the one that opens it — useful when the trigger is a small icon but the surface should align to a wider field
<Popover>
<PopoverAnchor asChild>
<div className="relative w-full max-w-sm">
<Input placeholder="Search projects" className="pr-9" />
<PopoverTrigger asChild>
<Button
variant="ghost"
size="icon"
aria-label="Search filters"
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7"
>
⚙
</Button>
</PopoverTrigger>
</div>
</PopoverAnchor>
<PopoverContent align="end" className="w-72">
<h4 className="font-medium">Filters</h4>
<p className="mt-1 text-sm text-muted-foreground">
Aligned to the input, opened by the gear icon.
</p>
</PopoverContent>
</Popover>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state |
defaultOpen | boolean | false | Default open state |
onOpenChange | function | — | Callback on open state change: (open: boolean) => void |
modal | boolean | false | When true, content outside the popover is inert |
AI Guidance
When to use
Use for inline forms, quick settings, info panels, or color pickers. Anchored to a trigger, non-modal, dismisses on outside click.
When not to use
Don't use for critical tasks that interrupt (use Dialog). Don't use for hover-only info (use Tooltip or HoverCard). Don't use for menu actions (use DropdownMenu).
Common mistakes
- Using Popover when the user must address the content (should be Dialog)
- Missing asChild on PopoverTrigger when using a styled Button
- Popover content too wide — keep it focused and compact
Accessibility
Radix manages focus, aria-expanded on the trigger, and closes on Escape. Content is portalled to body so stacking contexts don't clip it.
Related components
Token budget: 400
Verified against @hex-core/components@1.12.0