Link Preview
tool-ui/link-previewFreeBlock
Rich link previews with OG data.
See it running
Open the demo on tool-ui
www.tool-ui.com/components/link-previewInstall it
npx shadcn@latest add https://www.tool-ui.com/r/link-preview.jsonSource
1"use client";23import { Globe } from "lucide-react";4import { cn } from "./_adapter";56import {7 RATIO_CLASS_MAP,8 getFitClass,9 openSafeNavigationHref,10 sanitizeHref,11} from "../shared/media";12import type { SerializableLinkPreview } from "./schema";1314const FALLBACK_LOCALE = "en-US";15const CONTENT_SPACING = "px-5 py-4 gap-2";1617export interface LinkPreviewProps extends SerializableLinkPreview {18 className?: string;19 onNavigate?: (href: string, preview: SerializableLinkPreview) => void;20}2122export function LinkPreview(props: LinkPreviewProps) {23 const { className, onNavigate, ...serializable } = props;2425 const {26 id,27 href: rawHref,28 title,29 description,30 image,31 domain,32 favicon,33 ratio = "16:9",34 fit = "cover",35 locale: providedLocale,36 } = serializable;3738 const locale = providedLocale ?? FALLBACK_LOCALE;39 const sanitizedHref = sanitizeHref(rawHref);4041 const previewData: SerializableLinkPreview = {42 ...serializable,43 href: sanitizedHref ?? rawHref,44 locale,45 };4647 const handleClick = () => {48 if (!sanitizedHref) return;49 if (onNavigate) {50 onNavigate(sanitizedHref, previewData);51 } else {52 openSafeNavigationHref(sanitizedHref);53 }54 };5556 return (57 <article58 className={cn("relative w-full max-w-md min-w-80", className)}59 lang={locale}60 data-tool-ui-id={id}61 data-slot="link-preview"62 >63 <div64 className={cn(65 "group @container relative isolate flex w-full min-w-0 flex-col overflow-hidden rounded-xl",66 "border-border bg-card border text-sm shadow-xs",67 sanitizedHref && "cursor-pointer",68 )}69 onClick={sanitizedHref ? handleClick : undefined}70 role={sanitizedHref ? "link" : undefined}71 tabIndex={sanitizedHref ? 0 : undefined}72 onKeyDown={73 sanitizedHref74 ? (e) => {75 if (e.key === "Enter" || e.key === " ") {76 e.preventDefault();77 handleClick();78 }79 }80 : undefined81 }82 >83 <div className="flex flex-col">84 {image && (85 <div86 className={cn(87 "bg-muted relative w-full overflow-hidden",88 ratio !== "auto" ? RATIO_CLASS_MAP[ratio] : "aspect-[5/3]",89 )}90 >91 <img92 src={image}93 alt=""94 loading="lazy"95 decoding="async"96// … truncated
What it pulls in
npm packages
Files it writes
More from tool-ui
All 27 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Approval Cardapproval-card | tool-ui | Blocks | Free | 2 deps · 11 files | |
| Audioaudio | tool-ui | Blocks | Free | 2 deps · 9 files | |
| Chartchart | tool-ui | Blocks | Free | 2 deps · 8 files | |
| Citationcitation | tool-ui | Blocks | Free | 2 deps · 15 files | |
| Code Blockcode-block | tool-ui | Blocks | Free | 3 deps · 11 files | |
| Code Diffcode-diff | tool-ui | Blocks | Free | 3 deps · 10 files | |
| Data Tabledata-table | tool-ui | Blocks | Free | 1 dep · 17 files | |
| Geo Mapgeo-map | tool-ui | Blocks | Free | 4 deps · 12 files |
