Skip to content
WANCRAFT

B.69Cards & Containers

Link Preview

An inline link that springs out a preview card on hover or keyboard focus, with collision-aware placement.

NewReactMotionTailwindintermediate

Overview

Link Preview turns an inline link into a quiet peek at where it goes. After a short hover delay, or on keyboard focus, a card with an optional image, a meta line, a title and a description springs out of the link. You provide the content, so nothing is fetched. The card lives in the top layer (Popover API), sits above or below the link and flips or clamps to stay in the viewport, follows the pointer slightly along the link, and waits a moment before closing so the pointer can travel into it. Escape, blur or leaving dismisses it. On touch screens the first tap shows the preview with an explicit Open button and a second tap follows the link.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/link-preview.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/link-preview.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/link-preview.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { LinkPreview } from "@/components/ui/link-preview";

export function LinkPreviewExample() {
  return (
    <p>
      Built with
      <LinkPreview
        href="https://motion.dev"
        preview={{ title: "Motion for React", description: "A production-ready animation library.", meta: "motion.dev" }}
      >
        Motion
      </LinkPreview>
    </p>
  );
}

03Props

PropTypeDefaultDescription
hrefstring—Required. Link target; also used for the default meta line (hostname).
childrenReactNode—Required. Link text.
preview{ title: string; description?: string; image?: string; imageAlt?: string; meta?: string }—Required. Card content — provided by you, nothing is fetched.
side"top" | "bottom""top"Preferred side; flips when the other side has more room and clamps horizontally.
openDelaynumber350Hover / focus delay before opening, in ms.
closeDelaynumber180Delay before closing after the pointer leaves, so it can move into the card, in ms.
followCursorbooleantrueThe card drifts slightly (14%) with the pointer along the link, on a spring.
widthnumber300Card width in px, capped to the viewport.
accentstring"#FF7448"Underline, focus ring and touch Open button colour.
openLabelstring"Open link"Label of the Open button shown after a first tap on touch screens.
...propsAnchorHTMLAttributes—Forwarded to the <a> (target, rel, onClick…).

04Features

  • 01Hover with open delay, keyboard focus, and a close delay that lets the pointer move into the card
  • 02Top-layer card via the Popover API — never clipped by overflow or transformed ancestors
  • 03Prefers above / below, flips to the roomier side and clamps to the viewport; follows wrapped lines
  • 04Springs out of the link (transform-origin at the link) and drifts slightly with the pointer
  • 05Repositions on scroll and resize; Escape, blur, leaving or an outside tap dismisses it
  • 06Touch: first tap previews with an explicit Open button, second tap follows the link
motion · springinput · hoverinput · focusinput · pointerinput · clickinput · keyboard

05Accessibility

  • A real <a href> that works without the preview; the title and description are linked with aria-describedby (through a hidden element, so they are not read twice).
  • The card opens on keyboard focus (:focus-visible) and closes on Escape or blur.
  • For hover / focus the visual card is aria-hidden and contains nothing focusable; after a tap it becomes interactive and offers a real Open link.
  • Visible focus ring and a thicker underline while the card is open.
  • With prefers-reduced-motion the card only fades and does not follow the pointer.

06Limitations

  • Touch detection uses the pointer type of the tap, so a screen-reader double-tap on a touch device may also need two activations to follow the link.
  • In browsers without the Popover API the card falls back to position: fixed with a high z-index.