You must have encounter situation where you want to want to preview the link and for that you have to use external libraries. Now external libraries have their own advantages. But sometimes we just want our link preview component to be very simple and we don't want to fall into much complicated steps of using external libraries for example building our personal portfolio where we have to showcase our blogs that are published on different platforms.
Step1: Define preview componant
function LinkPreview({ url }) {
// State to hold the link preview data and loading status
const [previewData, setPreviewData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Fetches the link preview data when the URL prop changes
const fetchData = async () => {
try {
const response = await fetch(url);
const data = await response.text();
// Parsing logic to extract link preview data goes here
setLoading(false);
} catch (error) {
console.error(error);
setLoading(false);
}
};
fetchData();
}, [url]);
// Rendering logic for the link preview goes here
return (
// JSX code for rendering the link preview component
);
}
export default LinkPreview;
above code will take url as parameter and later process it. The previewData state will hold the link preview data, and the loading state will track the loading status while fetching the data.Next, we use the useEffect hook to fetch the link preview data when the url prop changes. Inside the fetchData function, we use the fetch function to make a request to the provided URL. Once we have the response, we extract the necessary data, such as title, description, and image, from the HTML response which you have seen written in head section of HTML code.
Step2: Extracting Link Preview Data
To extract the link preview data, we need to parse the HTML response and retrieve the relevant information. In this step, we will extract the title, description, and image using a basic parsing technique.
const parser = new DOMParser();
const doc = parser.parseFromString(data, 'text/html');
const title = doc.querySelector('title')?.textContent || '';
const description = doc.querySelector('meta[name="description"]')?.getAttribute('content') || '';
const image = doc.querySelector('meta[property="og:image"]')?.getAttribute('content') || '';
setPreviewData({ title, description, image });
It will create a new instance of the DOMParser and parse the HTML data using 'parser.parseFromString(data, 'text/html')', where data is the HTML response.
We will use 'doc.querySelector' to search for the required elements within the parsed HTML document.
Finally, we will update the previewData state with the extracted information by calling 'setPreviewData({ title, description, image })'.
Step3: Rendering the Link Preview
Now that we have the link preview data available, let's update the rendering logic in the return statement:
return (
<div>
<h3>{previewData.title}</h3>
<p>{previewData.description}</p>
{previewData.image && <img src={previewData.image} alt="Link Preview" />}
</div>
);
You can style the componant according to your choice, I am not doing because i sucks at designing. and that's all for the very simple link preview component.
Final result-
Now we can implement some error and loading state and with that we can also implement the redirect to website according to the link provided.
import { useState, useEffect } from 'react';
function LinkPreview({ url }) {
const [previewData, setPreviewData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const data = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(data, 'text/html');
const title = doc.querySelector('title')?.textContent || '';
const description = doc.querySelector('meta[name="description"]')?.getAttribute('content') || '';
const image = doc.querySelector('meta[property="og:image"]')?.getAttribute('content') || '';
setPreviewData({ title, description, image });
setLoading(false);
} catch (error) {
console.error(error);
setLoading(false);
}
};
fetchData();
}, [url]);
if (loading) {
return <p>Loading...</p>;
}
if (!previewData) {
return <p>Failed to fetch link preview.</p>;
}
const handleClick = () => {
window.open(url, '_blank');
};
return (
<div onClick={handleClick} style={{ cursor: 'pointer' }}>
<h3>{previewData.title}</h3>
<p>{previewData.description}</p>
{previewData.image && <img src={previewData.image} alt="Link Preview" />}
</div>
);
}
export default LinkPreview;
But what if it has a youtube video. The above code definately will not show the desired result. That what can we do?
well here is an escape:
We can check if a url is related to youtube or not and then using some methods we can extract the thumbnail of video for image section in link preview.
import { useState, useEffect } from 'react';
function LinkPreview({ url }) {
const [previewData, setPreviewData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const data = await response.text();
const isYouTubeVideo = isYouTubeURL(url);
if (isYouTubeVideo) {
const videoId = extractYouTubeVideoId(url);
const videoThumbnail = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;
setPreviewData({
videoId,
videoThumbnail,
});
setLoading(false);
} else {
const parser = new DOMParser();
const doc = parser.parseFromString(data, 'text/html');
const title = doc.querySelector('title')?.textContent || '';
const description = doc.querySelector('meta[name="description"]')?.getAttribute('content') || '';
const image = doc.querySelector('meta[property="og:image"]')?.getAttribute('content') || '';
setPreviewData({
title,
description,
image,
});
setLoading(false);
}
} catch (error) {
console.error(error);
setLoading(false);
}
};
fetchData();
}, [url]);
const isYouTubeURL = (url) => {
return url.includes('youtube.com') || url.includes('youtu.be');
};
const extractYouTubeVideoId = (url) => {
const videoIdRegex = /(?:\/embed\/|\/watch\?v=|\/(?:embed\/|v\/|watch\?.*v=|youtu\.be\/|embed\/|v=))([^&?#]+)/;
const match = url.match(videoIdRegex);
return match ? match[1] : '';
};
if (loading) {
return <p>Loading...</p>;
}
if (!previewData) {
return <p>Failed to fetch link preview.</p>;
}
const handleClick = () => {
window.open(url, '_blank');
};
if (previewData.videoId) {
return (
<div onClick={handleClick} style={{ cursor: 'pointer' }}>
<img src={previewData.videoThumbnail} alt="Video Thumbnail" />
</div>
);
}
return (
<div onClick={handleClick} style={{ cursor: 'pointer' }}>
<h3>{previewData.title}</h3>
<p>{previewData.description}</p>
{previewData.image && <img src={previewData.image} alt="Link Preview" />}
</div>
);
}
export default LinkPreview;
'isYoutubeUrl' function
It will check if youtube keyword is in there to sperate youtube link and normal link
'extractYouTubeVideoId' function-
It will be reponsible for extracting video ID,
The pattern
(?:\/embed\/|\/watch\?v=|\/(?:embed\/|v\/|watch\?.*v=|youtu\.be\/|embed\/|v=))([^&?#]+)
is used to match various YouTube URL formats, including 'embed', 'watch?v=, v/', 'watch?...v=', and 'youtu.be/'. The captured group ([^&?#]+) captures the video ID.
We then use the match method on the url string with the videoIdRegex to search for a match. If a match is found, the video ID is extracted using match[1]. If no match is found, the function returns an empty string.
And after finding we will get the thumbnail image easily.
and that's it.
Follow me on twitter - @Rahulj9a
Top comments (6)
Nice Idea :-)
Perhaps you could update the title of your post, and specify you use React ?
Thank you
Ya! i did that, i realise that after posting 😅
:-)
Challenge for you, try to do the same with vanjs.org/ an hundred times lighter than React, no bundler, directly in browser...🙂
It seems very simple but not effective. Because browser blocks response if cors header is not same as the origin domain. So the success rate of the fetch request is very low. You have no choice but to impliment this in backend
Hello, in case is useful for someone, I created a public API to extract metadata from any link, you can just call the endpoint, and build/display the preview.
thank you 😊