ComponentsOverlay
Popover
A floating panel that appears next to a trigger element. Built on Radix UI with configurable alignment, offset, and controlled state support.
Basic Popover
Alignment Variants
Use the align prop on PopoverContent to align the panel relative to the trigger.
Side Positioning
Use the side prop to control which side of the trigger the panel opens on.
With Form Content
Popovers are commonly used to contain small forms or settings panels.
Controlled State
Use open and onOpenChange to fully control when the popover is shown.
import { useState } from 'react';
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover/popover';
import { Button } from '@/components/ui/button/button';
export default function ControlledPopover() {
const [open, setOpen] = useState(false);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button variant="outline">{open ? 'Close' : 'Open'}</Button>
</PopoverTrigger>
<PopoverContent>
<p style={{ margin: 0 }}>Controlled popover content.</p>
<Button size="sm" onClick={() => setOpen(false)} style={{ marginTop: '0.75rem' }}>
Dismiss
</Button>
</PopoverContent>
</Popover>
);
}Installation
npx visor add popoverThis copies two files into your project:
components/ui/popover/popover.tsx— the componentcomponents/ui/popover/popover.module.css— the styles
Usage
import {
Popover,
PopoverTrigger,
PopoverContent,
} from '@/components/ui/popover/popover';
import { Button } from '@/components/ui/button/button';
export default function Example() {
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open</Button>
</PopoverTrigger>
<PopoverContent>
<p>Place content here.</p>
</PopoverContent>
</Popover>
);
}API Reference
PopoverProps
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state of the popover. |
onOpenChange | (open: boolean) => void | — | Callback when the open state changes. |
defaultOpen | boolean | false | Default open state for uncontrolled usage. |
side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | Side of the trigger the popover appears on (on PopoverContent). |
align | 'start' | 'center' | 'end' | 'center' | Alignment of the popover content relative to the trigger (on PopoverContent). |
sideOffset | number | 4 | Distance in pixels between the trigger and the popover (on PopoverContent). |
asChild | boolean | false | On PopoverTrigger — merges props onto the immediate child element instead of rendering a <button>. |
className | string | — | Additional CSS class names to merge onto PopoverContent. |
Sub-components
| Component | Element | Purpose |
|---|---|---|
Popover | Root | Context provider (wraps Radix Popover.Root) |
PopoverTrigger | <button> | The element that opens the popover; use asChild to wrap a custom trigger |
PopoverContent | Floating panel | The popover panel; accepts side, align, and sideOffset |
PopoverAnchor | Any element | Optional anchor to position the popover relative to a different element than the trigger |
Accessibility
- Built on Radix UI Popover —
role="dialog"andaria-expandedare applied automatically. - Focus moves into the popover when it opens and returns to the trigger when it closes.
- Pressing
Escapecloses the popover. - Clicking outside the popover closes it.
- For non-modal popovers containing only non-interactive content (e.g., tooltips), consider HoverCard instead.