Component
Popover
Anchored panel for contextual details or controls.
Text referenceSource and examples as JSON
npx -y github:anwarlemu/opencommerce-brand-cli#release add popover --surface siteRun from the target React 19.2+ app root with Tailwind CSS 4 and the @/* source alias.
Usage
Use for explanations, filters or small controls. Use variant="glass" over imagery or the header. Keep longer tasks in Dialog or Sheet.
- Forms longer than a few fields (use a dialog)
- Popovers that open on hover (use a tooltip)
- Gray panels
Exports: Popover, PopoverAnchor, PopoverContent, PopoverTrigger. This component includes a client boundary. Keep event handlers and state in a client component.
Dependencies: surface, @radix-ui/react-popover.
Example
import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Surface } from "@/lib/surface";
function Limits({ defaultOpen }: { defaultOpen?: boolean }) {
return (
<Popover defaultOpen={defaultOpen}>
<PopoverTrigger asChild>
<Button variant="secondary">What are limits?</Button>
</PopoverTrigger>
<PopoverContent className="grid gap-2">
<p className="font-display text-body-sm font-medium text-fg">Spending limits</p>
<p className="text-body-sm leading-relaxed text-fg-muted">Each card stops at its per purchase and monthly limits, whatever the agent tries to buy.</p>
</PopoverContent>
</Popover>
);
}
export function Site() {
return <Limits />;
}
export function Open() {
return (
<div className="h-48">
<Limits defaultOpen />
</div>
);
}
export function Glass() {
return (
<Surface ground="mist" className="h-60 rounded-panel p-8">
<Popover defaultOpen>
<PopoverTrigger asChild>
<Button variant="secondary">About monitoring</Button>
</PopoverTrigger>
<PopoverContent variant="glass" className="grid gap-1.5">
<p className="font-display text-body-sm font-medium">Every route, around the clock</p>
<p className="text-body-sm leading-relaxed text-fg-muted">Each store your agents buy from is exercised every few minutes, so a broken checkout is caught first.</p>
</PopoverContent>
</Popover>
</Surface>
);
}Source
"use client";
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { usePortalContainer } from "@/lib/surface";
import { cn } from "@/lib/utils";
// The brand's floating panel: white, a 9 percent ink edge, 8px corners and a soft drop, 6px off its trigger, growing out
// of the side nearest the trigger (scale 0.97 and a fade, 160ms ease-out). `glass` is the header's tray as a panel: white
// at 72 percent under a light sheen and a blur, a 10 percent ink edge. Reduced motion keeps only the fade.
const VARIANTS = {
default: "border-line bg-surface text-fg shadow-floating",
glass: "border-line-glass bg-glass bg-(image:--ds-glass-sheen) text-fg shadow-floating [backdrop-filter:var(--ds-glass-blur)]",
} as const;
function Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>) {
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
}
function PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
}
function PopoverContent({ className, align = "start", sideOffset = 6, collisionPadding = 8, variant = "default", ...props }: React.ComponentProps<typeof PopoverPrimitive.Content> & { variant?: keyof typeof VARIANTS }) {
return (
<PopoverPrimitive.Portal container={usePortalContainer()}>
<PopoverPrimitive.Content
data-slot="popover-content"
data-variant={variant}
align={align}
sideOffset={sideOffset}
collisionPadding={collisionPadding}
className={cn("z-50 w-72 max-w-(--radix-popover-content-available-width) max-h-(--radix-popover-content-available-height) overflow-y-auto overscroll-contain origin-(--radix-popover-content-transform-origin) animate-pop-in motion-reduce:animate-none rounded-control border p-4 text-body-sm outline-none", VARIANTS[variant], className)}
{...props}
/>
</PopoverPrimitive.Portal>
);
}
function PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
}
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };Reference: Extension from opencommerce-agentcard-web src/app/globals.css (.nav-tray, .win).