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>
| Prop | Type | Default | Description |
|---|---|---|---|
| children *required | ReactNode | — | |
| trigger *required | ReactNode | — | The trigger, usually a Link. |
| className | string | — | |
| closeDelay | number | 200 | |
| delay | number | 400 | |
| placement | Placement | '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>
triggeris usually aLink; keep it focusable so keyboard users can open the card.delay(default 400 ms) andcloseDelay(default 200 ms) control timing;placementdefaults tobottom.- The card may hold interactive content such as buttons. Width defaults to
w-72; passclassNameto change it. - Don’t put anything essential only in the card: the trigger must still make sense on its own.
Example source · show· hide
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