Skip to content
ContentLink previewMenu

Link preview

An unfurled link: a compact row or an expanded card with image, title and description, with a skeleton in the final layout and a plain-link fallback.

An expanded unfurl with an image and two compact rows.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/link-preview.json

Usage

tsx
import { LinkPreview } from "@/components/ui/chatcn/link-preview"

<LinkPreview
  variant="expanded"
  url="https://www.w3.org/WAI/ARIA/apg/patterns/treeview/"
  title="Tree View Pattern | APG"
  description="A tree view widget presents a hierarchical list."
  image={og.image}
  favicon={og.favicon}
/>

Fetch the metadata on your server and pass it in. The component never fetches anything itself.

Examples

Loading, no image and error

The skeleton matches the final layout block for block, so the card does not resize when data lands. It is static: no shimmer, no pulse. When unfurling fails, the link stays a link.

Skeletons in the final layout, a card without an image and the plain link fallback.

Props

PropTypeNotes
urlstringOpens in a new tab with noopener noreferrer
title, descriptionReactNodeWithout a title, the plain link renders
siteNameReactNodeDefaults to the domain
faviconstringFalls back to a globe
image, imageAltstringExpanded only, at 1.91:1
state"loading" | "ready" | "error"Default ready
variant"compact" | "expanded"Default compact

Keyboard

KeyAction
EnterOpen the link in a new tab

Accessibility

  • The whole card is one link, so it is one tab stop with one name.
  • Screen readers hear that it opens in a new tab. The arrow glyph is decorative.
  • While loading, the link is aria-busy and named after the domain.

Motion

  • Hover changes the background and hairline over 150 ms, on fine pointers only. The card never lifts or scales.