Marble UI
← Components

Hover Card / Preview Card

Preview: Profile

Rich, non-modal preview on hover, focus or long press (React Aria PreviewTrigger). May contain interactive content.

Import

import { HoverCard } from '@marbleui/ui'

Props

<HoverCard>

PropTypeDefaultDescription
children *requiredReactNode—
trigger *requiredReactNode—The trigger, usually a Link.
classNamestring—
closeDelaynumber200
delaynumber400
placementPlacement'bottom'

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitive: React Aria PreviewTrigger. Follow the primitive's docs for the full keyboard map.

Usage notes

Rich, non-modal preview shown on hover, focus or long press, such as a profile or issue summary behind a link. For a short text label use Tooltip; for content opened by click use Popover.

<HoverCard trigger={<Link href="/u/mayachen">@mayachen</Link>}>
  <p className="text-sm">UI engineer. Accessibility and design systems.</p>
</HoverCard>
  • trigger is usually a Link; keep it focusable so keyboard users can open the card.
  • delay (default 400 ms) and closeDelay (default 200 ms) control timing; placement defaults to bottom.
  • The card may hold interactive content such as buttons. Width defaults to w-72; pass className to change it.
  • Don’t put anything essential only in the card: the trigger must still make sense on its own.
Example source · show
import { Button } from '../button'
import { Link } from '../link'
import { HoverCard } from './hover-card'

const Profile = ({ initials, name, handle, bio }: { initials: string; name: string; handle: string; bio: string }) => (
  <div className="flex flex-col gap-3">
    <div className="flex items-center gap-3">
      <span className="grid size-10 shrink-0 place-items-center rounded-full bg-accent-soft text-sm font-semibold text-accent-soft-fg">
        {initials}
      </span>
      <div className="min-w-0">
        <div className="text-sm font-semibold">{name}</div>
        <div className="text-xs text-fg-muted">@{handle}</div>
      </div>
      <Button size="sm" variant="outline" className="ml-auto">Follow</Button>
    </div>
    <p className="text-sm text-fg-muted">{bio}</p>
  </div>
)

export const styles = {
  Profile: () => (
    <p className="max-w-sm text-sm text-fg-muted">
      Reviewed by{' '}
      <HoverCard trigger={<Link href="#">@mayachen</Link>}>
        <Profile initials="MC" name="Maya Chen" handle="mayachen" bio="UI engineer. Accessibility, design systems, good typography." />
      </HoverCard>{' '}
      and merged yesterday.
    </p>
  ),
  Preview: () => (
    <p className="max-w-sm text-sm text-fg-muted">
      See{' '}
      <HoverCard trigger={<Link variant="underline" href="#">ACME-142</Link>} className="w-80">
        <div className="flex flex-col gap-2">
          <div className="text-xs text-fg-subtle">ACME-142 · In progress</div>
          <div className="text-sm font-semibold text-fg">Fix login redirect after deep link</div>
          <p className="text-sm text-fg-muted">Users land on the dashboard instead of the page they requested.</p>
        </div>
      </HoverCard>{' '}
      for context.
    </p>
  ),
}

Source: packages/ui/src/hover-card/hover-card.tsx

Catalog

Category
overlays
Priority
Foundation
Primitive
react-aria
React Aria
PreviewTrigger
Base UI
Preview Card