Components
Popover
A floating panel that displays content triggered by a button click.
Popover
The Popover component displays floating content in a panel anchored to a trigger element. It's ideal for secondary information, quick actions, or compact forms that don't warrant a full dialog.
Use Popover for non-modal interactions. For modal content that requires user attention, use Dialog instead.
Features
- Trigger-based floating panel
- Automatic positioning with collision avoidance
- Focus management
- Modal and non-modal modes
- Controlled and uncontrolled state
- Keyboard accessible (Escape to close)
- Custom anchor support
Usage
import {
Popover,
PopoverTrigger,
PopoverContent,
} from '@loke/design-system/popover';
export default function Example() {
return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open Popover</Button>
</PopoverTrigger>
<PopoverContent>
<p>Popover content goes here.</p>
</PopoverContent>
</Popover>
);
}Tips:
- Use
asChildonPopoverTriggerto use your own button component. - PopoverContent auto-positions to avoid viewport edges.
- Set
modal={true}for focus trapping.
Props
Popover
Prop
Type
PopoverContent
Prop
Type
Examples
Basic popover
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open popover</Button>
</PopoverTrigger>
<PopoverContent className="w-80">
<div className="grid gap-4">
<div className="space-y-2">
<h4 className="font-medium leading-none">Dimensions</h4>
<p className="text-sm text-muted-foreground">
Set the dimensions for the layer.
</p>
</div>
<div className="grid gap-2">
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="width">Width</Label>
<Input id="width" defaultValue="100%" className="col-span-2" />
</div>
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="height">Height</Label>
<Input id="height" defaultValue="25px" className="col-span-2" />
</div>
</div>
</div>
</PopoverContent>
</Popover>Popover with form
<Popover>
<PopoverTrigger asChild>
<Button>Update settings</Button>
</PopoverTrigger>
<PopoverContent className="w-80">
<form className="grid gap-4">
<div className="space-y-2">
<h4 className="font-medium">Settings</h4>
</div>
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>
<Input id="name" placeholder="Enter name" />
</div>
<Button type="submit">Save</Button>
</form>
</PopoverContent>
</Popover>Positioning
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Top</Button>
</PopoverTrigger>
<PopoverContent side="top">
Content above trigger
</PopoverContent>
</Popover>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Right</Button>
</PopoverTrigger>
<PopoverContent side="right">
Content to the right
</PopoverContent>
</Popover>Controlled popover
Popover is closed
const [open, setOpen] = useState(false);
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button variant="outline">
{open ? "Close" : "Open"}
</Button>
</PopoverTrigger>
<PopoverContent>
<p>Controlled popover content</p>
<Button onClick={() => setOpen(false)}>Close</Button>
</PopoverContent>
</Popover>Accessibility
- Uses proper ARIA attributes for trigger and content.
- Focus moves to content when opened (in modal mode).
- Focus returns to trigger when closed.
- Escape key closes the popover.
- Click outside closes the popover.
- Content is properly announced to screen readers.
Best practices
- Keep popover content focused and concise.
- Use for secondary actions or additional information.
- Position popovers to avoid obscuring related content.
- Consider using Dialog for complex interactions.
- Avoid nesting popovers within popovers.
- Use controlled mode for programmatic control.