Hover Card
A rich preview card that appears on hover. Built on Radix UI HoverCard with scaleIn animation, configurable open/close delay, and arrow indicator.
Basic
A rich preview card that floats above content on hover. Ideal for user profiles, link previews, and contextual information panels. Built on Radix UI with a spring scaleIn entrance animation.
Installation
Install the component via the CLI in one command.
npx @work-rjkashyap/unified-ui add hover-cardpnpm dlx @work-rjkashyap/unified-ui add hover-cardnpx @work-rjkashyap/unified-ui add hover-cardbunx @work-rjkashyap/unified-ui add hover-cardIf you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.
Or install the full package
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm install @work-rjkashyap/unified-uipnpm add @work-rjkashyap/unified-uiyarn add @work-rjkashyap/unified-uibun add @work-rjkashyap/unified-uiAnatomy
import {
HoverCard,
HoverCardTrigger,
HoverCardContent,
Avatar,
Button,
Badge,
} from "@work-rjkashyap/unified-ui";Basic Usage
Wrap a trigger in HoverCardTrigger and your preview content in HoverCardContent. The card opens after a 200ms delay and closes after 150ms — preventing accidental triggers from quick cursor passes.
<HoverCard>
<HoverCardTrigger asChild>
<a href="/profile" className="underline text-primary">
@username
</a>
</HoverCardTrigger>
<HoverCardContent>
<p className="text-sm">Preview content goes here.</p>
</HoverCardContent>
</HoverCard>Placement
Use the side and align props on HoverCardContent to control where the card appears relative to the trigger.
side | Position |
|---|---|
top | Above the trigger |
bottom | Below the trigger (default) |
left | To the left of the trigger |
right | To the right of the trigger |
align | Alignment along the cross axis |
|---|---|
start | Aligned to the start edge of the trigger |
center | Centered against the trigger (default) |
end | Aligned to the end edge of the trigger |
Open & Close Delay
Control how long the user must hover before the card opens (openDelay) and how long before it closes when the cursor leaves (closeDelay).
{
/* Opens quickly, stays open longer */
}
<HoverCard openDelay={100} closeDelay={300}>
<HoverCardTrigger asChild>
<span className="underline cursor-help">Quick open</span>
</HoverCardTrigger>
<HoverCardContent>
<p className="text-sm">Opens after 100ms, closes after 300ms.</p>
</HoverCardContent>
</HoverCard>;
{
/* Default delays */
}
<HoverCard openDelay={200} closeDelay={150}>
...
</HoverCard>;The delay prevents the card from flickering when the cursor briefly passes over the trigger while moving to other elements.
User Profile Card
A rich user profile preview — the most common HoverCard pattern.
Posted by · 2 hours ago
Link Preview
Show a preview card for external or internal links on hover.
Custom Width
The default card width is w-64 (256px). Override it with a className on HoverCardContent.
{
/* Narrower */
}
<HoverCardContent className="w-48">...</HoverCardContent>;
{
/* Wider — for rich content */
}
<HoverCardContent className="w-80">...</HoverCardContent>;
{
/* Auto width based on content */
}
<HoverCardContent className="w-auto">...</HoverCardContent>;Side Offset
Use sideOffset to control the gap between the trigger and the card.
{
/* Default: 8px gap */
}
<HoverCardContent sideOffset={8}>...</HoverCardContent>;
{
/* Tighter: 4px gap */
}
<HoverCardContent sideOffset={4}>...</HoverCardContent>;
{
/* More breathing room: 12px gap */
}
<HoverCardContent sideOffset={12}>...</HoverCardContent>;Props
HoverCard
| Prop | Type | Default | Description |
|---|---|---|---|
openDelay | number | 200 | Milliseconds before the card opens after hover. |
closeDelay | number | 150 | Milliseconds before the card closes after cursor leaves. |
open | boolean | — | Controlled open state. |
defaultOpen | boolean | — | Initial open state (uncontrolled). |
onOpenChange | (open: boolean) => void | — | Callback when the open state changes. |
HoverCardTrigger
Uses Radix UI's HoverCardTrigger API. Use asChild to render the trigger as your own element (a <button>, <a>, or any other element).
HoverCardContent
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "bottom" | Which side of the trigger to render the card on. |
align | "start" | "center" | "end" | "center" | Alignment along the cross-axis. |
sideOffset | number | 8 | Pixel gap between the trigger and the card. |
className | string | — | Additional CSS classes (use to override width, padding, etc.). |
children | ReactNode | — | The preview content rendered inside the card. |
All other HoverCardContent props are forwarded to the underlying Radix HoverCardContent element.
Motion
- Open — Uses the
scaleInpreset:scale: 0.92 → 1,opacity: 0 → 1with a spring (stiffness: 300, damping: 24,mass: 0.8). - Close — Reverses the
scaleInanimation. - Arrow — The arrow indicator is rendered by Radix UI and inherits the card's position automatically.
- All animations respect
prefers-reduced-motionviauseReducedMotion()— falls back to a simpleopacitytransition.
Accessibility
- Built on @radix-ui/react-hover-card — fully WAI-ARIA compliant.
- The HoverCard is triggered on hover (pointer) and focus (keyboard users can tab to the trigger to see the card).
- The card content is in a portal, rendered at the document body level, ensuring proper z-index stacking above all page content.
HoverCardTrigger asChildpreserves the semantics of the host element — an<a>remains an<a>, a<button>remains a<button>.- The card is not
role="dialog"— it is supplementary preview content, not a focus trap. Do not put critical actions inside a HoverCard. - Avoid placing interactive elements (buttons, forms) inside a HoverCard. If interaction is needed, use a
Popoverinstead.
HoverCard vs Tooltip vs Popover
| Component | Trigger | Content | Interactive | Use Case |
|---|---|---|---|---|
Tooltip | Hover/Focus | Short text label | No | Brief descriptions for icons/buttons |
HoverCard | Hover/Focus | Rich preview | No* | Profile previews, link previews |
Popover | Click | Rich UI | Yes | Filters, settings, date pickers |
*Avoid interactive elements in HoverCard — use Popover for interactive content.
Design Tokens
| Token | Usage |
|---|---|
--popover | Card background color |
--popover-fg | Card text color |
--border | Card border color |
--radius-lg | Card border radius |
--shadow-lg | Card drop shadow |
--z-popover | Z-index for the floating card |