The Palos Publishing Company

Follow Us On The X Platform @PalosPublishing
Categories We Write About

Build a link previewer for blog editors

A link previewer for blog editors is a tool that generates a visual snippet or preview of a URL, typically including the page title, description, image, and sometimes other metadata. Below is a full implementation of a simple, production-ready React-based Link Previewer component ideal for integration into a blog editing environment.


✅ Features:

  • User pastes a link, preview auto-fetches metadata

  • Displays title, description, and thumbnail

  • Clean UI styled with Tailwind CSS

  • Robust error handling

  • Easily embeddable into blog editing tools


👇 Complete React Code (Using OpenGraph metadata)

tsx
// LinkPreviewer.tsx import React, { useState } from "react"; import axios from "axios"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Loader2, Link2Icon } from "lucide-react"; interface PreviewData { title: string; description: string; image: string; url: string; } export default function LinkPreviewer() { const [url, setUrl] = useState(""); const [preview, setPreview] = useState<PreviewData | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const fetchMetadata = async () => { if (!url) return; setLoading(true); setError(""); setPreview(null); try { const response = await axios.get(`/api/link-preview?url=${encodeURIComponent(url)}`); setPreview(response.data); } catch (err) { setError("Failed to fetch preview. Please check the URL."); } finally { setLoading(false); } }; return ( <div className="max-w-xl space-y-4"> <div className="flex gap-2"> <Input placeholder="Paste a URL" value={url} onChange={(e) => setUrl(e.target.value)} /> <Button onClick={fetchMetadata} disabled={loading || !url}> {loading ? <Loader2 className="animate-spin" /> : <Link2Icon />} </Button> </div> {error && <p className="text-red-500">{error}</p>} {preview && ( <Card className="rounded-2xl shadow-md hover:shadow-xl transition"> <CardContent className="p-4 flex flex-col gap-3"> {preview.image && ( <img src={preview.image} alt={preview.title} className="w-full h-48 object-cover rounded-lg" /> )} <h2 className="text-lg font-semibold">{preview.title}</h2> <p className="text-sm text-muted-foreground">{preview.description}</p> <a href={preview.url} target="_blank" rel="noopener noreferrer" className="text-blue-600 text-sm underline" > {preview.url} </a> </CardContent> </Card> )} </div> ); }

🧠 Backend (API Route to Fetch Metadata)

If using Next.js:

ts
// /pages/api/link-preview.ts import { NextApiRequest, NextApiResponse } from "next"; import axios from "axios"; import * as cheerio from "cheerio"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { url } = req.query; if (!url || typeof url !== "string") { return res.status(400).json({ error: "Missing URL" }); } try { const response = await axios.get(url); const $ = cheerio.load(response.data); const getMeta = (name: string) => $(`meta[property='${name}']`).attr("content") || $(`meta[name='${name}']`).attr("content"); const title = getMeta("og:title") || $("title").text(); const description = getMeta("og:description") || getMeta("description") || ""; const image = getMeta("og:image") || ""; const canonicalUrl = getMeta("og:url") || url; res.status(200).json({ title, description, image, url: canonicalUrl }); } catch (err) { res.status(500).json({ error: "Failed to fetch metadata" }); } }

🛠 Installation Notes

Ensure dependencies:

bash
npm install axios cheerio lucide-react

Tailwind and shadcn/ui must be set up in your project for this example to render as styled.


💡 Optional Enhancements

  • Cache previews in localStorage or on the server

  • Allow editing fetched metadata

  • Show previews inline in blog content

  • Support for YouTube, Twitter embeds using special handlers

  • Use iframe sandboxing for richer previews (with security considerations)


This link previewer works well for CMS/blog tools like custom Markdown editors or rich-text editors with URL parsing features.

Share this Page your favorite way: Click any app below to share.

Enter your email below to join The Palos Publishing Company Email List

We respect your email privacy

Categories We Write About