apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Sidebar
  • Stack
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
60 componentsapx-ds/renderer
HoverCard
Variant↳ other

Overlays

HoverCard

Hover-triggered rich preview overlay — the canonical \u201cGitHub user card\u201d / \u201clink preview\u201d / \u201cdefinition popup\u201d primitive. Compound API (

Overview

<HoverCard /> is the canonical hover-triggered rich preview overlay — the GitHub-user-card-on-@mention, the Stripe-style link preview, the inline glossary popup. It's Tooltip's interactive cousin and Popover's hover-driven sibling, sitting deliberately between them in the overlay family.

Overview — @mention profile preview on hover

Loading preview…
Overview.tsx
OverlayTriggerInteractive content?Focus trap?Default delay
<Tooltip />hover / focusNo (text-only)No400 / 150
<HoverCard />hover / focusYes (links, buttons OK)No700 / 300
<Popover />clickYesOptionaln/a
<Modal />clickYesYesn/a

HoverCard reuses Popover's positioning engine (usePosition, <Portal>, useEscapeStack) and Tooltip's hover-delay state machine (useTooltipDelay).

When to use

  • User profile card when hovering an @mention or avatar.
  • Link preview when hovering a URL inside running text.
  • Definition popup when hovering a glossary term (dotted-underline trigger).
  • Quick-view card when hovering a thumbnail / list-item title.
  • API endpoint preview when hovering a method name in docs.

When NOT to use

  • The content is non-interactive text → <Tooltip /> (smaller, snappier).
  • The content needs to persist until dismissed → <Popover /> (click trigger, optional focus trap).
  • The content blocks the rest of the page → <Modal /> (centered, modal).
  • The interaction is a list of actions → <Menu />.
  • The trigger is a non-focusable decorative element AND the content is the only path to the information → use <Popover /> instead, hover-only triggers are inaccessible by themselves.

Anatomy

text
<HoverCard>
  <HoverCard.Trigger asChild>
    <a href="…">trigger</a>            (any focusable element via asChild)
  </HoverCard.Trigger>
  <HoverCard.Content>
    {…rich content — links, buttons, avatars, anything…}
                                       (arrow auto-rendered by default)
  </HoverCard.Content>
</HoverCard>
<HoverCard>
  <HoverCard.Trigger asChild>
    <a href="…">trigger</a>            (any focusable element via asChild)
  </HoverCard.Trigger>
  <HoverCard.Content>
    {…rich content — links, buttons, avatars, anything…}
                                       (arrow auto-rendered by default)
  </HoverCard.Content>
</HoverCard>

Default behavior

  • Hover-focus mode (default) — opens on pointerenter or focus, closes on pointerleave (after delay) or blur (immediately). Keyboard-accessible by default.
  • Bridge pattern — moving the cursor from the trigger to the content cancels the close timer. Move out of both → the close timer fires. Lets users actually click the links / buttons inside the card.
  • No focus trap — Tab continues through Content as part of the natural document order. HoverCard is additive, not blocking. The card never steals focus when it opens.
  • Escape closes — integrated with the engine's useEscapeStack so nested overlays close in the right order (Tooltip-over-HoverCard or HoverCard-inside-Popover both work without per-component coordination).
  • Click does not toggle — clicking the trigger follows the trigger's own action (<a> navigates, <button> runs onClick). HoverCard is additive; it never steals the trigger's primary affordance.

Trigger modes

  • trigger="hover-focus" (default) — opens on hover and focus. Use for any keyboard-reachable trigger (links, buttons, focusable images).
  • trigger="hover" — hover-only. Discouraged because it locks out keyboard users; use only when the trigger is decorative and the content is reachable elsewhere.

Delay defaults

  • openDelay=700 — patient by design. HoverCard content is richer than a Tooltip; firing during incidental cursor sweeps would be visual noise.
  • closeDelay=300 — gives users time to traverse from trigger → content for clicking.

Override via <HoverCard openDelay={…} closeDelay={…}>. See the Delays example for the range.

Variants

Three visual variants × seven colors. solid is color-neutral (paper bg + neutral border) so the color prop is ignored; outline paints the border; soft paints the tinted background + low-opacity border + colored text.

Examples

Basic — @mention user card

Loading preview…
Basic.tsx

Link preview — inline URL hover card

Loading preview…
LinkPreview.tsx

Definition popup — glossary term

Loading preview…
DefinitionPopup.tsx

Async content — lazy-load on open

Loading preview…
AsyncContent.tsx

Variants — solid / outline / soft

Loading preview…
Variants.tsx

Sizes — sm / md / lg

Loading preview…
Sizes.tsx

Colors — soft variant palette

Loading preview…
Colors.tsx

Placements — anchor sides

Loading preview…
Placements.tsx

Delays — open / close timing

Loading preview…
Delays.tsx

No arrow — showArrow={false}

Loading preview…
NoArrow.tsx

Keyboard focus — hover-focus vs hover-only

Loading preview…
KeyboardFocus.tsx

Controlled — programmatic open / close

Loading preview…
Controlled.tsx

Accessibility

  • Trigger always carries its own role + accessible name (the consumer's element).
  • Trigger gets aria-describedby={contentId} while the card is open, pairing it with the Content element.
  • Content carries role="tooltip" per W3C HoverCard guidance — it's a description of the trigger, not a button-disclosed panel.
  • No aria-haspopup / aria-expanded — these are disclosure-widget attributes; HoverCard is not a disclosure.
  • Esc closes the topmost card via useEscapeStack.

Composition recipes

@mention profile card

tsx
<HoverCard onOpenChange={(open) => open && fetchProfile(id)}>
  <HoverCard.Trigger asChild>
    <a href={`/users/${username}`}>@{username}</a>
  </HoverCard.Trigger>
  <HoverCard.Content>
    {profile ? <ProfileCard data={profile} /> : <Spinner size="sm" />}
  </HoverCard.Content>
</HoverCard>
<HoverCard onOpenChange={(open) => open && fetchProfile(id)}>
  <HoverCard.Trigger asChild>
    <a href={`/users/${username}`}>@{username}</a>
  </HoverCard.Trigger>
  <HoverCard.Content>
    {profile ? <ProfileCard data={profile} /> : <Spinner size="sm" />}
  </HoverCard.Content>
</HoverCard>

Inline glossary

tsx
<HoverCard>
  <HoverCard.Trigger asChild>
    <button type="button" className="underline decoration-dotted">design token</button>
  </HoverCard.Trigger>
  <HoverCard.Content variant="soft" color="info">
    <strong>design token</strong>
    <p>A single source-of-truth value (color, spacing, …).</p>
  </HoverCard.Content>
</HoverCard>
<HoverCard>
  <HoverCard.Trigger asChild>
    <button type="button" className="underline decoration-dotted">design token</button>
  </HoverCard.Trigger>
  <HoverCard.Content variant="soft" color="info">
    <strong>design token</strong>
    <p>A single source-of-truth value (color, spacing, …).</p>
  </HoverCard.Content>
</HoverCard>

Async lazy-load

tsx
const [data, setData] = useState(null);
const loadOnce = (open: boolean) => open && data == null && fetchData().then(setData);

<HoverCard onOpenChange={loadOnce}>…</HoverCard>;
const [data, setData] = useState(null);
const loadOnce = (open: boolean) => open && data == null && fetchData().then(setData);

<HoverCard onOpenChange={loadOnce}>…</HoverCard>;

Related

  • <Tooltip /> — non-interactive text hint.
  • <Popover /> — click-triggered interactive panel.
  • <Modal /> — centered, focus-trapped overlay.

Props

PropTypeDefaultDescription
closeDelaynumber—Hover-out delay in ms before the card closes. Default: `300`.
closeOnEscapeboolean—Default: `true`. Esc closes the topmost HoverCard (escape-stack ordering).
defaultOpenboolean—Initial `open` for the uncontrolled case. Default: `false`.
onOpenChange(open: boolean) => void—Notified whenever the `open` value changes. The canonical async-content pattern hooks here: `onOpenChange={(open) => open && fetchUser(id)}` lets you defer the network request until the card actually opens.
openboolean—Controlled `open`. When omitted, the hover card manages its own state via `defaultOpen`.
openDelaynumber—Hover-in delay in ms before the card opens. Default: `700`. HoverCard's defaults are deliberately patient (vs Tooltip's 400ms) — these cards are richer / heavier to render and shouldn't fire during incidental cursor sweeps.
triggerenum—Open-trigger interaction mode. Default: `'hover-focus'`. - `hover-focus` — opens on pointer-enter **or** focus, closes on pointer-leave or blur. The accessible default for triggers that include keyboard-reachable content. - `hover` — opens on pointer-enter only. Use only when the trigger element is decorative or non-focusable; consumers must guarantee that the card's content is reachable elsewhere.