Components
For sighted users to preview content available behind a link.
Playground
w-64) by default — override with className. The trigger renders an <a>; use asChild to compose it with a link-styled Button or a framework Link.import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@workspace/ui/components/hover-card"
<HoverCard>
<HoverCardTrigger asChild>
<Button variant="link">@westy</Button>
</HoverCardTrigger>
<HoverCardContent>
<div className="flex gap-4">
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@westy" />
<AvatarFallback>WY</AvatarFallback>
</Avatar>
<div className="space-y-1">
<h4 className="font-medium">@westy</h4>
<p>Building a design system, one component at a time.</p>
<div className="flex items-center gap-2 pt-1 text-muted-foreground">
<CalendarBlankIcon className="size-4" />
<span className="text-xs">Joined August 2026</span>
</div>
</div>
</div>
</HoverCardContent>
</HoverCard>openDelay and closeDelay on the root control how long the pointer must rest before the card opens (700ms by default) and how long it lingers after leaving (300ms). Lower them for glossary-style hints; keep the defaults for previews so casual mouse travel does not flash cards open.<HoverCard openDelay={0} closeDelay={100}>
<HoverCardTrigger asChild>
<Button variant="link">Instant</Button>
</HoverCardTrigger>
<HoverCardContent className="w-56">
Opens as soon as the pointer arrives.
</HoverCardContent>
</HoverCard>
<HoverCard openDelay={1000} closeDelay={700}>
<HoverCardTrigger asChild>
<Button variant="link">Patient</Button>
</HoverCardTrigger>
<HoverCardContent className="w-56">
Waits a full second, then lingers on the way out.
</HoverCardContent>
</HoverCard>side, align and sideOffset. When there is not enough room, Radix flips the card to the opposite side automatically.<HoverCard>
<HoverCardTrigger asChild>
<Button variant="link">Top</Button>
</HoverCardTrigger>
<HoverCardContent side="top" className="w-56">
Above the trigger.
</HoverCardContent>
</HoverCard>
<HoverCard>
<HoverCardTrigger asChild>
<Button variant="link">Right, start</Button>
</HoverCardTrigger>
<HoverCardContent side="right" align="start" className="w-56">
To the right, aligned to the start.
</HoverCardContent>
</HoverCard>align is logical — start hugs the right edge of the trigger in RTL. side stays physical: "left" is the left regardless of direction.<div dir="rtl">
<HoverCard>
<HoverCardTrigger asChild>
<Button variant="link">@westy</Button>
</HoverCardTrigger>
<HoverCardContent align="start">
نبني نظام تصميم، مكوّنًا تلو الآخر.
</HoverCardContent>
</HoverCard>
</div><a> that should point somewhere real: the card previews the destination, the link remains the accessible path to it. Both parts carry data-state="open|closed" for styling.<a data-slot="hover-card-trigger" data-state="open" href="https://westy.la"> @westy </a> <div data-slot="hover-card-content" data-state="open" data-side="bottom" data-align="center"> Hover card content </div>
| Part | Prop | Type | Default |
|---|---|---|---|
| HoverCard | open | boolean | — |
| HoverCard | defaultOpen | boolean | false |
| HoverCard | onOpenChange | (open: boolean) => void | — |
| HoverCard | openDelay | number | 700 |
| HoverCard | closeDelay | number | 300 |
| HoverCardTrigger | asChild | boolean | false |
| HoverCardContent | side | "top" | "right" | "bottom" | "left" | "bottom" |
| HoverCardContent | align | "start" | "center" | "end" | "center" |
| HoverCardContent | sideOffset | number | 4 |
<HoverCard data-slot="hover-card" /> // Root — state container, renders nothing <HoverCardTrigger data-slot="hover-card-trigger" /> // <a>, opens on hover or focus <HoverCardContent data-slot="hover-card-content" /> // portaled panel (w-64, bg-popover)
Tokens used
6 design tokens consumed by the Hover Card component.
--popover
Popover
--popover-foreground
Popover Foreground
--foreground
Foreground
--text-sm
Text Small (14px)
--radius-lg
Radius 1× (10px)
--spacing
Spacing unit (4px)