Preview Card
A hover preview of a linked page: a thumbnail, the page's title, one line of description and its domain.
import {
PreviewCard,
PreviewCardArrow,
PreviewCardDescription,
PreviewCardDomain,
PreviewCardPopup,
PreviewCardThumb,
PreviewCardTitle,
PreviewCardTrigger,
} from '@fairgarden-private/design/components/PreviewCard'
The trigger is a Link, so it navigates and prints like any link. The card opens after 600 ms of hover and closes 300 ms after the pointer leaves. It appears only with hover and a fine pointer; on touch the link simply navigates. The card is the same anchored white panel as a Popover, with a --border-size-2 --primary12 frame, and it is hidden in print.
A preview card holds at most one link and is never the only route to its information.
A link preview
A link preview
PreviewCardThumb is a 16:9 image with the nested radius; give it alt, or an empty alt when the title already names it. The title is set in type-itemhead and the domain in mono.
From the saddle, the loop meets the Ridge Connector and drops to the reservoir. Hover the link with a mouse to preview it; on touch it simply navigates.
'use client'
import {
PreviewCard,
PreviewCardArrow,
PreviewCardDescription,
PreviewCardDomain,
PreviewCardPopup,
PreviewCardThumb,
PreviewCardTitle,
PreviewCardTrigger,
} from '@fairgarden-private/design/components/PreviewCard'
import styles from './basic.module.css'
export function PreviewCardBasic() {
return (
<p className={styles.text}>
From the saddle, the loop meets the{' '}
<PreviewCard>
<PreviewCardTrigger href="https://example.org/trails/ridge-connector">
Ridge Connector
</PreviewCardTrigger>
<PreviewCardPopup>
<PreviewCardArrow />
<PreviewCardThumb
render={
<svg viewBox="0 0 160 90" role="img" aria-label="Map sketch of the Ridge Connector">
<path className={styles.ridge} d="M0 72 40 44l30 16 40-36 50 34" />
<path className={styles.trail} d="M12 78c30-10 44-30 70-30s40-18 66-28" />
</svg>
}
className={styles.thumb}
/>
<PreviewCardTitle>Ridge Connector</PreviewCardTitle>
<PreviewCardDescription>A 2.1 km link from the saddle to the reservoir dam.</PreviewCardDescription>
<PreviewCardDomain>example.org</PreviewCardDomain>
</PreviewCardPopup>
</PreviewCard>{' '}
and drops to the reservoir. Hover the link with a mouse to preview it; on touch it simply
navigates.
</p>
)
}
API Reference
PreviewCard and PreviewCardTrigger
Groups the parts of a preview card (Base UI PreviewCard.Root).
The link that opens the card on hover. Renders a Link (§9.3), inline
by default, so it navigates and prints like any link [D79]. The card is
never the only route to its information.
| Prop | Type | Description |
|---|---|---|
external | | Adds the arrow-open mark and “(external site)” for assistive technology.
Default |
handle | | Associates a detached trigger with a PreviewCard created by |
index | | Adds the screen-only visited ✓ used in long indexes, such as reference
and archive lists. Default |
kind | | Which build: |
list | | With |
muted | | Rests in |
payload | | A payload handed to the PreviewCard’s children function when this trigger opens it. |
primary | | Primary Radix scale: the link text and focus ring. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale: the accent underline. Never defaulted; omitted, it inherits the scope. |
delay | | Hover time before the card opens, in ms. Default 600. |
closeDelay | | Time after the pointer leaves before the card closes, in ms. Default 300. |
className | | Extra class names, added after the module’s own. |
PreviewCardPopup and PreviewCardArrow
The preview panel, rendered in its Base UI Portal as a nested white
scope: --primary1 face, --border-size-2 --primary12 frame, --ds-radius-8,
240–360 px wide. Compose PreviewCardThumb, PreviewCardTitle,
PreviewCardDescription and PreviewCardDomain inside it, and
PreviewCardArrow for the tail. It holds at most one link.
| Prop | Type | Description |
|---|---|---|
primary | | Primary Radix scale inside the popup’s |
secondary | | Secondary Radix scale inside the popup: accents only. |
container | | The element the portal renders into. Default: |
align | | Alignment to the link. Default |
side | | Which side of the link the card sits on. Default |
sideOffset | | Distance from the link in px. Default 8 ( |
collisionPadding | | Clearance from the viewport edge in px. Default 16. |
The tail: a --ds-space-12 × 6 px triangle whose --border-size-2 edge continues the frame.
PreviewCardThumb, PreviewCardTitle, PreviewCardDescription and PreviewCardDomain
The page’s thumbnail: a --ratio-widescreen photograph with the nested
radius (--ds-radius-8 − --size-px-3, floored at --radius-1) [D40].
Give it alt (empty when the title already names it).
The linked page’s title, in type-itemhead --primary12.
A one-line description, in type-body-ui --primary12.
The page’s domain, in type-data --role-muted (mono measures).
Additional types
previewCard
type previewCard = previewCardPreviewCardArrowProps
Props for PreviewCardArrow: Base UI PreviewCard.Arrow props.
type PreviewCardArrowProps = PreviewCardArrow.PreviewCardArrowPropsPreviewCardDescriptionProps
Props for PreviewCardDescription: p props and render.
type PreviewCardDescriptionProps = useRender.ComponentProps<'p'>PreviewCardDomainProps
Props for PreviewCardDomain: p props and render.
type PreviewCardDomainProps = useRender.ComponentProps<'p'>PreviewCardPopupProps
Props for PreviewCardPopup: Base UI PreviewCard.Popup props plus placement, color axes and portal options.
type PreviewCardPopupProps = PreviewCardPopupProps & {
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
side?: Side;
align?: Align;
sideOffset?: number | OffsetFunction;
collisionPadding?: Padding;
container?: HTMLElement | ShadowRoot | React.RefObject<HTMLElement | ShadowRoot | null> | null;
}PreviewCardProps
Props for PreviewCard: Base UI PreviewCard.Root props (open, onOpenChange …).
type PreviewCardProps<Payload = unknown> = PreviewCardRoot.Props<Payload>PreviewCardThumbProps
Props for PreviewCardThumb: img props and render.
type PreviewCardThumbProps = useRender.ComponentProps<'img'>PreviewCardTitleProps
Props for PreviewCardTitle: p props and render.
type PreviewCardTitleProps = useRender.ComponentProps<'p'>PreviewCardTriggerProps
Props for PreviewCardTrigger: Link props plus the hover delays and Base UI’s trigger options.
type PreviewCardTriggerProps = {
/**
* Which build: `inline` (default) underlines in running text; `standalone`
* is the caps module link with a trailing ›; `nav` has no rest underline
* and marks the current page; `title` stretches over a card or list item;
* `noteref` and `backref` are the note call and return (§9.3).
*/
kind?: 'nav' | 'title' | 'inline' | 'standalone' | 'backref' | 'noteref' | null;
/**
* Adds the screen-only visited ✓ used in long indexes, such as reference
* and archive lists. Default `false` [D174, D175].
*/
index?: boolean | null;
/**
* Adds the arrow-open mark and "(external site)" for assistive technology.
* Default `false`.
*/
external?: boolean | null;
/**
* With `kind="nav"`: a list link (nav-panel, footer, drawer and breadcrumb
* lists), whose hover is `--role-link-hover` color only, plus the
* `--ds-stroke-1-5` `--role-accent` underline where that ink is
* `--primary12`. Without it, `nav` is bare navigation text (bar and
* utility items, page numbers, toolbar links), whose hover is the
* `--border-size-2` `--role-accent` underline (§9.3) [D181]. Default
* `false`.
*/
list?: boolean | null;
/**
* Rests in `--role-muted` instead of `--primary12`, as a breadcrumb's
* ancestors. Hover takes `--role-link-hover` only (the underline is added
* where that ink is `--primary12`); with `kind="nav"` it replaces the bar
* item's bare-text underline (§9.3, §9.8) [D181]. Default `false`.
*/
muted?: boolean | null;
/**
* Primary Radix scale: the link text and focus ring. Never defaulted;
* omitted, it inherits the scope [D133].
*/
primary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
/**
* Secondary Radix scale: the accent underline. Never defaulted; omitted,
* it inherits the scope.
*/
secondary?:
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
/** Extra class names, added after the module's own. */
className?: string;
/** Hover time before the card opens, in ms. Default 600. */
delay?: number;
/** Time after the pointer leaves before the card closes, in ms. Default 300. */
closeDelay?: number;
/** Associates a detached trigger with a PreviewCard created by `PreviewCard.createHandle`. */
handle?: PreviewCardHandle<unknown>;
/** A payload handed to the PreviewCard's children function when this trigger opens it. */
payload?: unknown;
}Specification: DESIGN-SYSTEM.md §10.15 (preview card), §9.3 (link) and §7.6 (link notes in print).