HoverCard
A non-modal floating panel that surfaces a rich preview when the user hovers or focuses a trigger.
Opens on pointer hover and on keyboard focus; content is supplementary — primary info should also be reachable from the trigger.
Preview
tsx
import { HoverCard, HoverCardContent, HoverCardTrigger, Link } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<HoverCard>
<HoverCardTrigger asChild>
<Link href="#">@jane</Link>
</HoverCardTrigger>
<HoverCardContent>
<div style={{ display: 'grid', gap: '0.25rem' }}>
<strong>Jane Doe</strong>
<span>Design engineer building component systems.</span>
</div>
</HoverCardContent>
</HoverCard>
);
}
Variants
Section titled “Variants”Delays
Section titled “Delays”Tune the hover-in and hover-out behaviour with openDelay (default 700 ms) and closeDelay (default 300 ms). Shorter values feel snappier; longer values prevent the card from flickering on accidental hovers.
Preview
tsx
import { HoverCard, HoverCardContent, HoverCardTrigger, Link } from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<div style={{ display: 'flex', gap: '1.5rem', flexWrap: 'wrap' }}>
<HoverCard openDelay={0} closeDelay={0}>
<HoverCardTrigger asChild>
<Link href="#">Instant</Link>
</HoverCardTrigger>
<HoverCardContent>
<div>openDelay=0 / closeDelay=0</div>
</HoverCardContent>
</HoverCard>
<HoverCard openDelay={300} closeDelay={150}>
<HoverCardTrigger asChild>
<Link href="#">Quick</Link>
</HoverCardTrigger>
<HoverCardContent>
<div>openDelay=300 / closeDelay=150</div>
</HoverCardContent>
</HoverCard>
<HoverCard openDelay={1000} closeDelay={600}>
<HoverCardTrigger asChild>
<Link href="#">Patient</Link>
</HoverCardTrigger>
<HoverCardContent>
<div>openDelay=1000 / closeDelay=600</div>
</HoverCardContent>
</HoverCard>
</div>
);
}
With arrow
Section titled “With arrow”Add HoverCardArrow inside HoverCardContent to render a directional pointer toward the trigger.
Preview
tsx
import {
HoverCard,
HoverCardArrow,
HoverCardContent,
HoverCardTrigger,
Link,
} from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<HoverCard>
<HoverCardTrigger asChild>
<Link href="#">Cynosure docs</Link>
</HoverCardTrigger>
<HoverCardContent>
<div style={{ display: 'grid', gap: '0.25rem', maxWidth: '16rem' }}>
<strong>Cynosure</strong>
<span style={{ fontSize: '0.875rem' }}>
A design system for React applications. Hover for a quick preview.
</span>
</div>
<HoverCardArrow />
</HoverCardContent>
</HoverCard>
);
}
Profile preview
Section titled “Profile preview”A typical layout pairs an avatar, name, handle, and a short bio.
Preview
tsx
import {
Avatar,
HoverCard,
HoverCardContent,
HoverCardTrigger,
Link,
} from '@arshad-shah/cynosure-react';
export default function Example() {
return (
<p style={{ fontSize: '0.95rem', lineHeight: 1.6, maxWidth: '32rem' }}>
Pull request reviewed by{' '}
<HoverCard>
<HoverCardTrigger asChild>
<Link href="#">@alex</Link>
</HoverCardTrigger>
<HoverCardContent>
<div style={{ display: 'flex', gap: '0.75rem', maxWidth: '18rem' }}>
<Avatar name="Alex Park" />
<div style={{ display: 'grid', gap: '0.125rem' }}>
<strong>Alex Park</strong>
<span
style={{ color: 'var(--cynosure-color-foreground-muted)', fontSize: '0.8125rem' }}
>
@alex · Engineering
</span>
<span style={{ fontSize: '0.8125rem', marginTop: '0.25rem' }}>
Working on the design system. Reviews every Tuesday and Thursday.
</span>
</div>
</div>
</HoverCardContent>
</HoverCard>{' '}
and approved this morning.
</p>
);
}
PropTypeDefaultDescription
side
"top"|"right"|"bottom"|"left"
bottom
Preferred placement.
align
"center"|"start"|"end"
center
Alignment along the side.
sideOffset
number
8
Distance (px) from the trigger.
alignOffset
number
0
Offset (px) along the alignment axis.
collisionPadding
number
8
Viewport padding for collision detection.
container
HTMLElement|(() => HTMLElement)
—
Portal target — defaults to `document.body`.
withArrow
boolean
true
Render a caret pointing at the trigger. The caret is side-aware and stays
aimed at the trigger when the card flips or shifts.
children
ReactNode
—
Card body.
Accessibility
Section titled “Accessibility”- Opens on
pointerenterand on keyboardfocus, giving keyboard users parity with mouse users. - The hover card is non-modal — focus is not trapped and the rest of the page remains interactive.
- Treat the content as supplementary. Primary actions and identifying information must also live in the trigger so touch users (who never hover) still see them.
openDelayandcloseDelayadjust the timing of show / hide without affecting accessibility semantics.
Recipes
Section titled “Recipes”- Use for user profile cards, link previews, footnotes, and definition popovers.
- Combine with
AvatarandAnchorto build a recognisable mention preview. - Prefer
Tooltipfor short text-only hints andPopoverfor click-triggered content with focusable controls. - Anchor it to inline text by wrapping a
HoverCardTrigger asChildaround the link element itself.