Popover
Floating contextual panel.
Preview
Code
import { Button } from "@/components/ui/button";
import {
Popover, PopoverContent, PopoverDescription,
PopoverHeader, PopoverTitle, PopoverTrigger,
} from "@/components/ui/popover";
export function Example() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline">Open popover</Button>} />
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Settings</PopoverTitle>
<PopoverDescription>Manage your notification preferences.</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | — | Controlled open state. |
| defaultOpen | boolean | — | Uncontrolled initial open state. |
| onOpenChange | (open: boolean) => void | — | Called when the open state changes. |
Sub-components
PopoverTrigger— Element that opens the popover. Supports `render` for asChild.PopoverContent— The floating popup. Portals to body.| Prop | Type | Default | Description |
|---|---|---|---|
| sideOffset | number | 8 | Pixel gap between trigger and popover. |
| variant | "solid" | "glass" | "solid" | Surface treatment. glass (C3 only) for floating over canvas content. |
| showCloseButton | boolean | false | Render an X close button. |
PopoverHeader— Top section with title + description.PopoverTitle— Wired to `aria-labelledby`.PopoverDescription— Wired to `aria-describedby`.Built on Base UI Popover.
All components also accept standard HTML attributes for their root element (e.g. `id`, `aria-*`, `data-*`, event handlers) and forward `ref` where applicable.
Source
The full implementation of components/ui/popover.tsx is below — copy it into your project and own it. Some components import the cn helper from lib/utils or other primitives; copy those too.
"use client";
import { cn } from "@/lib/utils";
import { Popover as BasePopover } from "@base-ui-components/react/popover";
import { X } from "lucide-react";
import type { ComponentPropsWithoutRef, ReactNode } from "react";
export const Popover = BasePopover.Root;
export const PopoverTrigger = BasePopover.Trigger;
export const PopoverClose = BasePopover.Close;
export function PopoverContent({
className,
children,
sideOffset = 8,
variant = "solid",
showCloseButton = false,
...props
}: ComponentPropsWithoutRef<typeof BasePopover.Popup> & {
sideOffset?: number;
variant?: "solid" | "glass";
showCloseButton?: boolean;
children?: ReactNode;
}) {
return (
<BasePopover.Portal>
<BasePopover.Positioner sideOffset={sideOffset}>
<BasePopover.Popup
className={cn(
"z-50 w-72 rounded-lg border border-border p-4 shadow-md",
variant === "glass" ? "surface-glass-panel" : "bg-surface-elevated",
"data-[starting-style]:opacity-0 data-[starting-style]:scale-95",
"data-[ending-style]:opacity-0 data-[ending-style]:scale-95",
"transition-all duration-150",
className,
)}
{...props}
>
{children}
{showCloseButton && (
<BasePopover.Close
className={cn(
"absolute right-3 top-3 rounded-sm text-fg-muted opacity-70 transition-opacity",
"hover:opacity-100 focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
)}
aria-label="Close"
>
<X className="h-4 w-4" />
</BasePopover.Close>
)}
</BasePopover.Popup>
</BasePopover.Positioner>
</BasePopover.Portal>
);
}
export function PopoverHeader({ className, ...props }: ComponentPropsWithoutRef<"div">) {
return <div className={cn("mb-2 flex flex-col gap-1", className)} {...props} />;
}
export function PopoverTitle({
className,
...props
}: ComponentPropsWithoutRef<typeof BasePopover.Title>) {
return (
<BasePopover.Title className={cn("text-sm font-semibold text-fg", className)} {...props} />
);
}
export function PopoverDescription({
className,
...props
}: ComponentPropsWithoutRef<typeof BasePopover.Description>) {
return <BasePopover.Description className={cn("text-sm text-fg-muted", className)} {...props} />;
}JavaFX
Ships in the PRIZM JavaFX library for thick-client C3 apps as PrizmPopover (extends PopupControl). Run the gallery to see it natively.
import design.prizm.fx.controls.PrizmPopover;
PrizmPopover()
PrizmPopover(Node content)| Prop | Type | Default | Description |
|---|---|---|---|
| setContent | (Node) → void | — | The body; compose it yourself (e.g. a VBox of labels). |
| show | (Node owner) → void | — | Show anchored below the owner; auto-fixes on-screen. Inherited show(owner, x, y) for custom placement. |
Built on PopupControl, so its content inherits the owner scene's PRIZM theme (like Tooltip / ContextMenu). Auto-hides on focus loss, styled by the .prizm-popover rules. The web `glass` variant is NOT ported. Mirrors components/ui/popover.tsx.