HoverCard
A Radix-backed hover preview — point at a trigger and a rich card reveals on a small delay (no click). For sighted-pointer enrichment, not essential actions; the same content should be reachable another way for keyboard/touch users.
Import
import { Avatar, HoverCard } from "@roger-emerson/ploxum-primitives";Usage
<HoverCard>
<HoverCard.Trigger asChild>
<button type="button" className="text-[13px] underline-offset-2 hover:underline">
Dana Okafor
</button>
</HoverCard.Trigger>
<HoverCard.Content width={260}>
<div className="flex items-center gap-3">
<Avatar name="Dana Okafor" src="/crew/dana.jpg" status="live" />
<div>
<div className="text-[13px] font-medium">Dana Okafor</div>
<div className="text-[12px] text-muted-foreground">Show Caller · On shift</div>
</div>
</div>
</HoverCard.Content>
</HoverCard>Props
HoverCard (root)
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | — | Uncontrolled initial state. |
onOpenChange | (open: boolean) => void | — | Open-state callback. |
openDelay | number | 200 | Hover dwell (ms) before the card reveals. |
closeDelay | number | 150 | Delay (ms) before the card hides after the pointer leaves. |
children | ReactNode | — | Trigger + Content. |
HoverCard.Trigger
Radix Trigger passthrough — use asChild to wrap your own anchor (a link, name chip, or Avatar). Keep the trigger a real focusable element so the relationship is discoverable.
HoverCard.Content
| Prop | Type | Default | Description |
|---|---|---|---|
align | "start" | "center" | "end" | "center" | Alignment relative to the trigger. |
side | "top" | "right" | "bottom" | "left" | "bottom" | Preferred side; flips on collision. |
sideOffset | number | 6 | Gap from the trigger in px. |
width | number | — | Fixed width in px. Defaults to content-sized with a 220px floor. |
className | string | — | Merged onto the panel. |
Also accepts the remaining Radix HoverCard.Content props (collisionPadding, avoidCollisions, …).
Design rules
- HoverCard is pointer-only enrichment — it opens on hover, never on click or focus-by-keyboard. Don't put an action a user must take inside it; mirror that content somewhere keyboard- and touch-reachable.
- Does not trap focus and is not a menu. For an anchored surface with interactive controls that needs focus management, use
Popover(heuristic 9); for command items, useDropdownMenu. - The panel animates a 200ms fade/scale on the
cubic-bezier(0.25, 1, 0.5, 1)ease — within the motion budget, reduced-motion gated. Don't extend it. - Keep the dwell honest: the default
openDelay(200ms) avoids flicker on incidental pointer travel. Lower it only for a deliberately fast-preview surface.
