Preview Card
A card that appears when a link is hovered, so a reader can see where it goes without going there.
Findings were compared against the prior chest radiograph of 14 March, which showed no consolidation.
Installation
npx shadcn@latest add https://qure-ui.qure.ai/r/preview-card.jsonUsage
import {
PreviewCard, PreviewCardBody, PreviewCardContent,
PreviewCardDescription, PreviewCardMeta, PreviewCardTitle, PreviewCardTrigger,
} from '@/components/ui/preview-card'<PreviewCard>
<PreviewCardTrigger href="/studies/ACC-4409123">chest radiograph of 14 March</PreviewCardTrigger>
<PreviewCardContent>
<PreviewCardBody>
<PreviewCardTitle>CR Chest PA — 14 March 2026</PreviewCardTitle>
<PreviewCardDescription>Reported as clear.</PreviewCardDescription>
</PreviewCardBody>
</PreviewCardContent>
</PreviewCard>What it is for, and what it is not
It answers "what is this?" without spending a navigation — the patient behind a name in a worklist, the study behind an accession number, the guideline behind a citation.
It is not a Tooltip. A tooltip names a control in a few words, cannot be entered with the pointer, and holds no links. This holds a card's worth of content, stays open while you move onto it, and can contain links of its own.
It is not a Popover either: a popover opens on click and can hold controls a user must operate. A preview card opens on hover, which means it also opens by accident.
Everything in a preview card must be reachable another way. It never appears on a touch screen, it never appears for a user who navigates by voice, and a keyboard user only gets it by focusing the link. Content that is only in the card is content most of your users cannot see.
Composition
<PreviewCard> {/* owns open state; optionally a handle */}
<PreviewCardTrigger /> {/* an <a>. delay and closeDelay live here */}
<PreviewCardContent> {/* portal + positioner + popup */}
<PreviewCardMedia /> {/* optional full-bleed strip: a key image */}
<PreviewCardBody>
<PreviewCardTitle />
<PreviewCardDescription />
<PreviewCardMeta /> {/* a <dl> of accession, modality, referrer */}
</PreviewCardBody>
</PreviewCardContent>
</PreviewCard>The popup is not clipped, because the arrow is one of its children and an overflow on the popup
would eat it. PreviewCardMedia and PreviewCardBody do their own clipping instead.
A patient summary
The card takes other components — a Badge for acuity, an Avatar for the assigned reader. Keep it to what a reader needs in order to decide whether to open the study; a preview that has to be scrolled has stopped being a preview.
One card for a whole worklist
- Sunita DeshmukhACC-4471902
- Michael OkaforACC-4471887
- Aditi RaoACC-4471863
Thirty rows should not mount thirty popups. createPreviewCardHandle() makes a handle; each
trigger passes its row as payload, and one root renders from whichever trigger opened it by
taking a function as its children.
The payload is typed — createPreviewCardHandle<Study>() — and arrives as undefined before any
trigger has been used, so the render function has to handle that case.
Placement
side is a preference rather than a promise: Base UI flips the card when there is no room, which
is why the arrow reads its own placement off data-side rather than being told where to point.
showArrow is off by default — with an 8px offset the card already reads as belonging to the
link, and an arrow adds a second thing pointing at it.
Delays
delay and closeDelay are props on PreviewCardTrigger, not on the root — unlike
Tooltip, where they sit on the provider. The defaults are 600ms and 300ms.
600ms is long on purpose. A card that fires at 150ms turns a paragraph of links into a flicker show as the pointer crosses it, and the closing delay is what lets you move diagonally from the link onto the card without it vanishing on the way.
Keyboard
Tab to the link and the card opens on focus; Escape closes it. It does not trap focus and it is not a dialog — links inside it are reached by tabbing on, and it stays open while they are focused.
API Reference
Everything Base UI's Preview Card accepts.
On PreviewCardTrigger:
Prop
Type
On PreviewCardContent — the positioning props are forwarded to Base UI's Positioner:
Prop
Type