affectUI › Components › Data display

Hover Card

A preview of what a link or name points to – opens after a short rest of the pointer or on keyboard focus, stays while the pointer moves into it, never on touch, flips to stay on screen.

Free and open source (MIT). Install: npx shadcn@latest add https://www.affectui.com/r/hover-card.json · Import from @/components/ui/hover-card

When to use

  • A peek at what a name or link points to without leaving the page – an agent, a person, a file, a run, a pull request
  • Mentions in feeds, logs and tables, where the full page is one click away but a glance is often enough

When not to use

  • The name of an icon button or a short hint – use the Tooltip
  • Anything people must act on, or a form – use the Popover, which opens on a press
  • Information that only lives in the card – touch screens never show it; keep it on the page the link opens
  • Actions on the thing under the pointer – use the Context Menu

Usage

import { HoverCard } from "@/components/ui/hover-card";

export function AgentName({ agent }: { agent: { id: string; name: string; role: string; status: string } }) {
  return (
    <HoverCard
      width={288}
      content={
        <div>
          <strong>{agent.name}</strong>
          <p>{agent.role} · {agent.status}</p>
          <a href={`/agents/${agent.id}`}>Open agent</a>
        </div>
      }
    >
      <a href={`/agents/${agent.id}`}>{agent.name}</a>
    </HoverCard>
  );
}

Props

NameTypeDefaultDescription
contentReactNodeWhat the card shows – the card brings its padding, edge and shadow, you bring the inside. Empty or null: only the trigger is rendered
childrenReactElementExactly one element that takes a ref and focus – usually a link. Its own handlers run first; one that calls preventDefault keeps the card out of it. The card is a <div> right after it – inside running text, use a <div> rather than a <p> around it, as HTML doesn't allow a <div> in a <p>
side"bottom" | "top" | "right" | "left""bottom"Where it opens; flips to the other side when that has more room
align"start" | "center" | "end""start"Which edges of card and trigger line up; switches when the card would stick out. start and end follow the reading direction
offsetnumber8Gap to the trigger in px
openDelaynumber600How long the pointer rests (or the keyboard focus stays) before it opens, in ms – passing over a list opens nothing
closeDelaynumber300How long it stays after the pointer leaves trigger and card, in ms
widthnumber | stringThe card's width; by default it fits its content, up to 320px
open / onOpenChangeboolean / (open) => voidControls it from outside; leave open out and it opens on its own
disabledbooleanNever opens
classNamestringA class for the card

Keyboard

  • Tab: Focusing the trigger opens the card after the wait; Tab again moves into the card's links, and on past them it closes
  • Esc: Close the card – the focus goes back to the trigger when it was inside
  • Enter: Follows the link, as always

Accessibility

  • The trigger stays an ordinary link or button – its name, role and Enter are untouched
  • The card follows the trigger in the page, so Tab reaches its links right after the trigger and screen readers find it there
  • Keyboard focus opens it like hovering does (only :focus-visible – a click's focus doesn't)
  • Treat it as a preview: whatever it shows must also be on the page the link opens, since touch never shows it
  • Escape closes it first, so a dialog around it stays open; links inside get the library's focus ring

Responsive

  • The grace area: on the way from the trigger into the card, the pointer may cross the gap (and the corridor to the card's far corners) without it closing
  • Only one card at a time; it lives in the top layer (popover), so no overflow cuts it, follows its trigger on scroll and flips to stay on screen – a tall card scrolls
  • Touch never opens it: a tap follows the link, and a tap anywhere else closes one that is open
  • Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"

Requirements

  • React 19

Related

  • Tooltip – A small dark label for one control – shows on hover after a short wait and at once under keyboard focus, neighbours follow instantly, an optional shortcut inside, flips to stay on screen
  • Popover – A small floating card attached to its trigger – a title and quiet line, any content, flips to stay on screen, closes on a press outside or Escape and hands the focus back
  • Avatar – A person's picture or initials on a soft color of their own – rounded squares for workspaces, an agent's pixel mark that twinkles while it works, a status dot and a group that overlaps and ends in +N
  • Context Menu – The menu a right-click opens, right at the pointer – a long press on touch, Shift F10 from the keyboard, items built for what was clicked, with icons, shortcuts, checks, red items and submenus