# Preview Card

Preview a link’s destination without leaving the current page.

User profile preview

[Complete TSX file](/examples/preview-card/default.tsx)

```tsx
"use client";

import { Avatar, AvatarFallback } from "@/siteplane/components/avatar";
import {
  PreviewCard,
  PreviewCardPopup,
  PreviewCardTrigger,
} from "@/siteplane/components/preview-card";

export default function Example() {
  return (
    <p className="text-sm">
      Assigned to{" "}
      <PreviewCard>
        <PreviewCardTrigger
          className="font-medium underline underline-offset-4"
          href="#ben-carter"
        >
          @ben
        </PreviewCardTrigger>
        <PreviewCardPopup>
          <div className="flex gap-3">
            <Avatar className="size-10">
              <AvatarFallback>BC</AvatarFallback>
            </Avatar>
            <div className="grid min-w-0 gap-1">
              <p className="font-medium">Ben Carter</p>
              <p className="text-muted-foreground">
                Product designer on the web team.
              </p>
              <p className="text-muted-foreground text-xs">Joined March 2024</p>
            </div>
          </div>
        </PreviewCardPopup>
      </PreviewCard>
    </p>
  );
}
```

## Installation

Complete [one-time setup](/docs/installation/) first.

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/preview-card
```

With npm: `npx shadcn@4.18.0 add @siteplane/preview-card`. [Registry JSON](/registry/preview-card.json) lists source files and dependencies.

For this page’s examples, also install:

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/avatar @siteplane/progress
```

## Usage

```tsx
import {
  PreviewCard,
  PreviewCardTrigger,
  PreviewCardPopup,
} from "@/siteplane/components/preview-card";

<PreviewCard>
  <PreviewCardTrigger href="#website-redesign">
    Website Redesign
  </PreviewCardTrigger>
  <PreviewCardPopup>New marketing site, due October 30.</PreviewCardPopup>
</PreviewCard>;
```

## Composition

```text
PreviewCard
├── PreviewCardTrigger (link)
└── PreviewCardPopup
```

## Link preview

Show where a link leads, such as a project, so people can decide whether to open it. The popup is 256px wide by default; give `PreviewCardPopup` a width such as `w-80` when the content needs more room. This card pairs a project icon and title with a two-line description, and keeps the details compact with a [Progress](/docs/components/progress/) bar and the due date. The trigger stays a regular link, so it still works for people who don’t hover.

Project link preview

[Complete TSX file](/examples/preview-card/link-preview.tsx)

```tsx
"use client";

import { LayoutTemplateIcon } from "lucide-react";
import {
  PreviewCard,
  PreviewCardPopup,
  PreviewCardTrigger,
} from "@/siteplane/components/preview-card";
import { Progress } from "@/siteplane/components/progress";

export default function Example() {
  return (
    <p className="text-sm">
      The latest designs are in{" "}
      <PreviewCard>
        <PreviewCardTrigger
          className="font-medium underline underline-offset-4"
          href="#website-redesign"
        >
          Website Redesign
        </PreviewCardTrigger>
        <PreviewCardPopup className="w-80">
          <div className="grid w-full min-w-0 gap-3">
            <div className="flex min-w-0 items-start gap-3">
              <LayoutTemplateIcon
                aria-hidden="true"
                className="size-5 shrink-0 text-muted-foreground"
              />
              <div className="grid min-w-0 gap-0.5">
                <p className="font-medium leading-5">Website Redesign</p>
                <p className="line-clamp-2 text-muted-foreground text-xs leading-5">
                  New marketing site with a refreshed homepage and pricing page.
                </p>
              </div>
            </div>
            <div className="grid gap-2">
              <Progress aria-label="Tasks done" max={18} size="sm" value={12} />
              <p className="flex items-center justify-between gap-3 text-muted-foreground text-xs">
                <span>12 of 18 tasks done</span>
                <span>Due October 30</span>
              </p>
            </div>
          </div>
        </PreviewCardPopup>
      </PreviewCard>
      .
    </p>
  );
}
```

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| PreviewCardTrigger.delay | number | 600 | Milliseconds before the card opens. |
| PreviewCardTrigger.closeDelay | number | 300 | Milliseconds before the card closes. |
| PreviewCardPopup.side | Positioner side | bottom | Side of the anchor the card opens on. |
| PreviewCardPopup.align | start \| center \| end | center | Positioner alignment. |
| PreviewCardPopup.sideOffset | Positioner sideOffset | 4 | Gap from anchor. |
| PreviewCardPopup.alignOffset | Positioner alignOffset | 0 | Shift along the anchor's edge. |
| PreviewCardPopup.anchor | Positioner anchor | trigger | Custom anchor. |
| PreviewCardPopup.portalProps | PreviewCardPrimitive.Portal.Props | unset | Portal options. |
| open / defaultOpen | boolean | false | Controlled or initial visibility. |
| onOpenChange | (open, eventDetails) => void | unset | Visibility callback. |
PreviewCard is the foundation Root; Trigger preserves link behavior; Popup
includes Portal and Positioner and defaults to a padded w-64 surface. Its
className is a string. `PreviewCardPrimitive` exposes [Base UI Preview
Card](https://base-ui.com/react/components/preview-card). There is no
PreviewCardContent alias or complete positioner-props bag; Popup takes the
positioner's side, align, sideOffset, alignOffset and anchor directly. Other
trigger props, refs and root behavior follow the foundation.

[Read the installed source](/source/preview-card).

## Usage notes

Keep the destination understandable without hovering. The card is supplementary and should not contain required actions; use Popover or Dialog for a keyboard-driven interaction.
