HoverCard
A popover card revealed on hover/focus with collision-aware positioning and directional arrow.
Installation
npx vayu-ui init #one time onlynpx vayu-ui add hovercardnpx vayu-ui add -t hovercard #with test case needsUsage
Basic
Sides
Rich content
<HoverCard
content={
<div className="w-48">
<p className="font-semibold text-sm">Preview</p>
<p className="text-xs text-muted-content">
Rich content on hover.
</p>
</div>
}
>
<button>Hover me</button>
</HoverCard>
<HoverCard
side="right"
align="start"
content={
<div className="w-48">
<p className="font-semibold text-sm">User Profile</p>
<p className="text-xs text-muted-content">
john@example.com
</p>
</div>
}
>
<button>Hover for profile</button>
</HoverCard>
<HoverCard
openDelay={500}
closeDelay={100}
showArrow={false}
content={
<div className="w-48">
<p className="font-semibold text-sm">Delayed Card</p>
<p className="text-xs text-muted-content">
Opens slowly, closes quickly.
</p>
</div>
}
>
<button>Hover me slowly</button>
</HoverCard>Anatomy
HoverCard— Root container that wraps the trigger elementHoverCardArrow— Directional arrow pointing to the trigger (internal)
The HoverCard component uses a compound-like pattern where you pass the trigger as children and the card content via the content prop.
Accessibility
- Keyboard support: Tab to focus, Escape to dismiss
- Focus management: Card opens on focus and closes on blur
- ARIA attributes:
aria-haspopup="true"— Indicates the trigger displays a popuparia-expanded— Reflects open/closed statearia-describedby— Links trigger to card content viauseId
- Delays: Configurable
openDelayandcloseDelayprevent accidental triggers - Disabled state: Set
disabled={true}to disable hover behavior
Screen reader behavior
Screen readers announce the trigger element normally. When focused, the card content becomes available via aria-describedby, allowing screen readers to read the content as additional description. The aria-expanded state change is also announced when the card opens or closes.
Component Folder Structure
HoverCard/
├── HoverCard.tsx # Root component with portal rendering
├── HoverCardArrow.tsx # Directional arrow component
├── hooks.ts # Positioning and open/close logic
├── types.ts # Type definitions
├── index.ts # Public API exports
└── README.md # Component documentationProps
HoverCard
| Prop | Type | Default | Description |
|---|---|---|---|
content | ReactNode | — | Card content |
side | 'top' | 'right' | 'bottom' | 'left' | "bottom" | Preferred side |
align | 'start' | 'center' | 'end' | "center" | Alignment along the edge |
sideOffset | number | 8 | Gap between trigger and card (px) |
alignOffset | number | 0 | Alignment shift (px) |
openDelay | number | 200 | Delay before opening (ms) |
closeDelay | number | 300 | Delay before closing (ms) |
contentClassName | string | — | Extra class on the card container |
disabled | boolean | false | Disable the hover card entirely |
showArrow | boolean | true | Show the directional arrow |
className | string | — | Extra class on the trigger wrapper |