← ui

web-preview-facts

lib

a link's six facts and its host as shown; fetches nothing, safe in a browser

npx shadcn add @ag/web-preview-facts
Already installed? Preview an update
npx shadcn add @ag/web-preview-facts --dry-run

Your installed source stays unchanged until you update it. How updates work

Latest changes · 2026-10-16
  • New: Unfurl and hostOf, moved out of web-preview-unfurl, plus hrefOf (a link as an address: as written when it names a scheme, else on https). It fetches nothing, so a browser can import it. Migration: import Unfurl and hostOf from lib/web-preview-facts instead of lib/web-preview-unfurl.
Updated 2026-10-16 · release notes

shelf social & links

part of web-preview

used by web-feed, web-preview-unfurl, browser

hostsitetitleimage
youtube.comYouTube[1hr Talk] Intro to Large Language Modelsyes
paulgraham.compaulgraham.comDo Things that Don't Scalenone
github.comGitHubGitHub - Lulzx/cuda-metalyes

Six facts per link, fetched ONCE where the network is (mise unfurl <url>) and shipped as data. A browser cannot read a foreign page (CORS) and a build that fetches on every deploy depends on the other site being up; the card is a pure function of these.

the demo above, verbatim

web-preview-facts.demo.tsx
import { Sample } from "@/app/samples"
import { hostOf, type Unfurl } from "@/registry/base-nova/lib/web-preview-facts"

/** What `mise unfurl <url>` printed for these, pasted here as data: the whole point.
 *  Nothing on this page fetched anything. */
// #region facts
const FACTS: Unfurl[] = [
  {
    url: "https://www.youtube.com/watch?v=zjkBMFhNj_g",
    site: "YouTube",
    title: "[1hr Talk] Intro to Large Language Models",
    description: "Andrej Karpathy",
    image: "/xtldr-preview-karpathy.jpg",
  },
  {
    url: "https://paulgraham.com/ds.html",
    site: "paulgraham.com",
    title: "Do Things that Don't Scale",
    description:
      "One of the most common types of advice we give at Y Combinator is to do things that don't scale.",
  },
  {
    url: "https://github.com/Lulzx/cuda-metal",
    site: "GitHub",
    title: "GitHub - Lulzx/cuda-metal",
    description: "CUDA compiler and runtime for Apple Silicon",
    image: "/xtldr-preview-cuda-metal.png",
  },
]
// #endregion

export default function Demo() {
  return (
    <Sample name="facts" title="the facts of three links" with="facts">
      <div className="space-y-6">
        <table className="w-full font-mono text-xs">
          <thead className="text-muted-foreground">
            <tr className="text-left">
              <th className="pb-2 font-normal">host</th>
              <th className="pb-2 font-normal">site</th>
              <th className="pb-2 font-normal">title</th>
              <th className="pb-2 font-normal">image</th>
            </tr>
          </thead>
          <tbody>
            {FACTS.map((f) => (
              <tr key={f.url} className="border-border border-t">
                <td className="py-2">{hostOf(f.url)}</td>
                <td className="py-2">{f.site}</td>
                <td className="py-2">{f.title}</td>
                <td className="py-2">{f.image ? "yes" : "none"}</td>
              </tr>
            ))}
          </tbody>
        </table>
        <p className="max-w-prose text-muted-foreground text-sm">
          Six facts per link, fetched ONCE where the network is (
          <code className="font-mono text-xs">mise unfurl &lt;url&gt;</code>)
          and shipped as data. A browser cannot read a foreign page (CORS) and a
          build that fetches on every deploy depends on the other site being up;
          the card is a pure function of these.
        </p>
      </div>
    </Sample>
  )
}

the source, every file an install writes

web-preview-facts.ts
// THE FACTS OF A LINK. A web preview is drawn from six facts: the url, the site, a
// title, a description, an image, an icon. This module owns their type and how a link
// is written and shown (`hrefOf`, `hostOf`), and fetches nothing, so it is safe in a
// browser: the card (web-preview) and the browser window read it there. The fetch that
// reads the facts from a page is `web-preview-unfurl`, a server's.

export interface Unfurl {
  url: string
  /** The site's own name (og:site_name), else its host. */
  site: string
  title: string
  description?: string
  /** Absolute URL of the preview image (og:image, twitter:image). */
  image?: string
  /** Absolute URL of the site's icon, when the page names one. */
  favicon?: string
}

/** A link as an address: as written when it names its scheme (`https://`,
 *  `file://`, which a fetch then refuses), else on https (`example.com/x`). */
export function hrefOf(url: string): string {
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`
}

/** The host a link is shown as: no scheme, no `www.`, no path. */
export function hostOf(url: string): string {
  return new URL(hrefOf(url)).hostname.replace(/^www\./, "")
}