Popover
A floating panel anchored to a trigger, with title and description primitives.
Preview
popover-demo
Installation
pnpm dlx shadcn@latest add http://localhost:3000/r/popover.jsonSource
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
import { cn } from "@/lib/utils";
function Popover({ ...props }: PopoverPrimitive.Root.Props) {
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
}
function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
}
function PopoverPortal({ ...props }: PopoverPrimitive.Portal.Props) {
return <PopoverPrimitive.Portal data-slot="popover-portal" {...props} />;
}
function PopoverContent({
className,
align = "center",
side = "bottom",
sideOffset = 6,
alignOffset = 0,
children,
...props
}: PopoverPrimitive.Popup.Props &
Pick<PopoverPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
return (
<PopoverPortal>
<PopoverPrimitive.Positioner
align={align}
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
collisionPadding={8}
className="isolate z-50"
>
<PopoverPrimitive.Popup
data-slot="popover-content"
className={cn(
"relative z-50 w-56 origin-(--transform-origin) rounded-lg bg-popover p-3 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 transition-[opacity,scale] duration-100 ease-out outline-none data-ending-style:scale-95 data-ending-style:opacity-0 data-starting-style:scale-95 data-starting-style:opacity-0 motion-reduce:transition-none",
className,
)}
{...props}
>
<PopoverPrimitive.Arrow
data-slot="popover-arrow"
className="relative block h-1.5 w-3 overflow-clip before:absolute before:bottom-0 before:left-1/2 before:size-[calc(6px*sqrt(2))] before:transform-[translate(-50%,50%)_rotate(45deg)] before:border before:border-foreground/10 before:bg-popover before:content-[''] data-[side=bottom]:-top-1.5 data-[side=left]:-right-2.25 data-[side=left]:rotate-90 data-[side=right]:-left-2.25 data-[side=right]:-rotate-90 data-[side=top]:-bottom-1.5 data-[side=top]:rotate-180"
/>
{children}
</PopoverPrimitive.Popup>
</PopoverPrimitive.Positioner>
</PopoverPortal>
);
}
function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
return (
<PopoverPrimitive.Title
data-slot="popover-title"
className={cn("text-sm leading-none font-medium", className)}
{...props}
/>
);
}
function PopoverDescription({ className, ...props }: PopoverPrimitive.Description.Props) {
return (
<PopoverPrimitive.Description
data-slot="popover-description"
className={cn("text-xs text-muted-foreground", className)}
{...props}
/>
);
}
function PopoverClose({ ...props }: PopoverPrimitive.Close.Props) {
return <PopoverPrimitive.Close data-slot="popover-close" {...props} />;
}
export {
Popover,
PopoverClose,
PopoverContent,
PopoverDescription,
PopoverPortal,
PopoverTitle,
PopoverTrigger,
};Props
PopoverContent
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "bottom" | "left" | "right" | "bottom" | Preferred side of the trigger. |
sideOffset | number | 6 | Pixel offset from the trigger. |
align | "start" | "center" | "end" | "center" | Alignment relative to the trigger. |
alignOffset | number | 0 | Pixel offset along the alignment axis. |
className | string | - | Adds custom classes to the popup. |