VayuUI

HoverCard

A popover card revealed on hover/focus with collision-aware positioning and directional arrow.

Installation

npx vayu-ui init #one time only
npx vayu-ui add hovercard
npx vayu-ui add -t hovercard #with test case needs

Usage

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 element
  • HoverCardArrow — 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 popup
    • aria-expanded — Reflects open/closed state
    • aria-describedby — Links trigger to card content via useId
  • Delays: Configurable openDelay and closeDelay prevent 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 documentation

Props

HoverCard

PropTypeDefaultDescription
contentReactNodeCard content
side'top' | 'right' | 'bottom' | 'left'"bottom"Preferred side
align'start' | 'center' | 'end'"center"Alignment along the edge
sideOffsetnumber8Gap between trigger and card (px)
alignOffsetnumber0Alignment shift (px)
openDelaynumber200Delay before opening (ms)
closeDelaynumber300Delay before closing (ms)
contentClassNamestringExtra class on the card container
disabledbooleanfalseDisable the hover card entirely
showArrowbooleantrueShow the directional arrow
classNamestringExtra class on the trigger wrapper

On this page