Popover
FreeA small panel anchored to a trigger for quick settings or details.
pnpm dlx shadcn@latest add https://caliperui.site/r/popover.jsonNo reminder yet.
When to use #
Use it for
- Quick settings that should not leave the page.
- Content that needs controls inside it.
Skip it when
- The content is only a label; use a tooltip.
- The decision blocks everything else; use a dialog.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/popover.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above. It is built from Popover, PopoverTrigger, PopoverClose, PopoverAnchor and PopoverContent.
import { Calendar } from "lucide-react" import { useState } from "react" import { Button } from "@/components/ui/button" import { SegmentedControl } from "@/components/ui/segmented-control" import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" export function QuickSettings() { const [open, setOpen] = useState(false); const [remind, setRemind] = useState("3"); const [saved, setSaved] = useState<string | null>(null); const dates: Record<string, string> = { "1": "13 Oct", "3": "11 Oct", "7": "7 Oct" }; return ( <div className="grid justify-items-center gap-3 pb-40"> <Popover open={open} onOpenChange={setOpen}> <PopoverTrigger asChild> <Button variant="secondary" size="sm"><Calendar aria-hidden="true" />Due 14 Oct · remind {remind === "7" ? "1 week" : `${remind} day${remind === "1" ? "" : "s"}`} before</Button> </PopoverTrigger> <PopoverContent arrow aria-label="Reminder" className="grid gap-3"> <p className="text-sm font-medium">Remind Ostra Freight</p> <SegmentedControl label="Remind before" value={remind} onValueChange={setRemind} options={[{ value: "1", label: "1 day" }, { value: "3", label: "3 days" }, { value: "7", label: "1 week" }]} /> <p className="text-xs text-muted-foreground">Sends the invoice again with a pay link on {dates[remind]}.</p> <div className="flex justify-end gap-2"> <Button variant="ghost" size="sm" onClick={() => setOpen(false)}>Cancel</Button> <Button size="sm" onClick={() => { setSaved(dates[remind]); setOpen(false); }}>Save reminder</Button> </div> </PopoverContent> </Popover> <p role="status" className="text-sm text-muted-foreground">{saved ? `Reminder set for ${saved}, 09:00 in Ostra Freight’s time zone.` : "No reminder yet."}</p> </div> ); }
API reference #
Popover
component
No props of its own; it accepts the native props of its root element.
PopoverTrigger
component
No props of its own; it accepts the native props of its root element.
PopoverClose
component
No props of its own; it accepts the native props of its root element.
PopoverAnchor
component
No props of its own; it accepts the native props of its root element.
PopoverContent
component
Also accepts the native props of its root element and a ref.
Accessibility #
It is built on native elements, so roles and focus come from the browser.
Keyboard and focus handling comes from Radix popover: arrow keys move through items, Enter and Space select, and Escape closes and returns focus.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.