Hover card
Hover or focus preview panel for profiles, links, and contextual details.
Composition
The preferred shape for composing the installed primitive from its exported parts.
Parts
Exported compound parts from the installed source.
HoverCard ├── HoverCardTrigger └── HoverCardContent
First install and activate one skin. Core deliberately contains no visual token defaults.
The Control UI source installs this primitive from src/registry/sources/control-ui/ui/hover-card.tsx. Install it on its own with the command above, or inspect the source below.
npx shadcn@latest add https://control-ui.dev/r/hover-card.jsonKnobs
Typed custom properties the recipe paints with. Set one on the root — style, a utility class, or a skin — and every slot inherits it.
--cui-popup-* · 16 knobsHow the cascade resolves--cui-popup-radius*var(--radius-popover)--cui-popup-background<color>var(--popover)--cui-popup-foreground<color>var(--popover-foreground)--cui-popup-border-color<color>var(--border)--cui-popup-border-width<length>1px--cui-popup-shadow*var(--shadow-pop)--cui-popup-backdrop-filter*blur(var(--backdrop-blur-popover))--cui-popup-backdrop-background<color>oklch(from var(--foreground) l c h / var(--overlay-opacity))--cui-popup-item-radius<length-percentage>var(--radius-popup-item)--cui-popup-item-foreground<color>var(--foreground)--cui-popup-item-highlight-background<color>oklch(from var(--foreground) l c h / 0.06)--cui-popup-item-highlight-foreground<color>var(--cui-popup-item-foreground)--cui-popup-item-highlight-muted-foreground<color>var(--muted-foreground)--cui-popup-item-disabled-opacity<number>0.4--cui-popup-separator-color<color>var(--border)--cui-popup-shortcut-foreground<color>var(--muted-foreground)Installed dependencies
Support files installed with this primitive — shared ones arrive once with your first Control UI component. Public dependencies stay linked to their own pages.
src/registry/sources/control-ui/surface-variants.tsSupportRaw code
This primitive's source and the support files it installs with
"use client";import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card";import type { ComponentProps, CSSProperties, ReactNode } from "react";import type { OpenChangeEventDetails } from "@/components/control-ui/control-props";import type { PopupKnobStyle } from "@/components/control-ui/knob-contracts/popup-knobs";import { cn } from "@/components/control-ui/lib/cn";import { skinEffects, skinId } from "@/components/control-ui/skin";export type HoverCardProps = { children?: ReactNode; open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean, eventDetails: OpenChangeEventDetails) => void;};export type HoverCardContentProps = Omit< ComponentProps<"div"> & { side?: "top" | "bottom" | "left" | "right"; align?: "start" | "center" | "end"; sideOffset?: number; }, "style"> & { style?: CSSProperties & PopupKnobStyle };// Base UI PreviewCard behind shadcn-shaped facade, so shadcn HoverCard snippets compose verbatim.export function HoverCard(props: HoverCardProps) { return <PreviewCardPrimitive.Root {...props} />;}export function HoverCardTrigger({ className, ...props}: ComponentProps<typeof PreviewCardPrimitive.Trigger> & { style?: CSSProperties & PopupKnobStyle }) { return ( <PreviewCardPrimitive.Trigger data-control-ui="hover-card" data-control-family="popup" data-popup-kind="hover-card" data-slot="trigger" className={className} {...props} /> );}export function HoverCardContent({ className, children, side = "bottom", align = "center", sideOffset = 8, ...props}: HoverCardContentProps) { return ( <PreviewCardPrimitive.Portal> {/* portal escapes every token-scoped ancestor, so scope is re-asserted here */} <PreviewCardPrimitive.Positioner data-control-ui="hover-card" data-popup-kind="hover-card" data-control-family="popup" data-slot="positioner" data-skin={skinId()} data-effects={skinEffects()} side={side} align={align} sideOffset={sideOffset} className="z-[80]" > <PreviewCardPrimitive.Popup data-control-ui="hover-card" data-popup-kind="hover-card" data-control-family="popup" data-slot="content" data-surface="floating" data-popup-part="surface" className={cn("w-64 p-[var(--popover-padding)]", className)} {...props} > {children} </PreviewCardPrimitive.Popup> </PreviewCardPrimitive.Positioner> </PreviewCardPrimitive.Portal> );}