I love not only blogging but read blogs too! Traditionally, when bloggers state some scientific-based facts or refer to other posts, they have to add a link to sources.
The question for readers is, whether it would be worth to stop reading the post and switch to reading a source now?
Because along with the post, we might have up to 10 links to different sources. Which can we skip then?
That's why nowadays, the link content previewer is a must-have feature for blogs and even chats. You have seen them already in many different forms on Facebook, LinkedIn, Twitter, WhatsApp, etc.
The main benefit of the link content previewer is that readers can have some expectations of what they are going to read later before they follow the link.
Usually, a link content previewer contains the domain name (URL), the title, text, and an image. You can also create it with more information by providing more data to its content.
In this post, I will show you how you can quickly develop a link content previewer feature for your blog with React, Vue, and Vanilla JavaScript.
From simple to more complicated concepts, let's start with Vanilla JavaScript implementation:
Part I: Link content previewer with VanillaJS
The first step is to add straightforward text content to the index.html
:
<!--index.html-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Link Content Previewer</title>
</head>
<body>
<div class="wrapper">
<p>Hi there! π</p>
<p>I would like to share some frontend tips and tricks that
I have already applied to some of my projects.</p>
<p>Happily coming back with <br/> my
<a href="https://dev.to/ilonacodes/frontend-shorts-vue-js-vanilla-js-digital-dices-og"
class="link-with-preview"
>
frontend shorts
</a>
series on
<a href="https://dev.to"
class="link-with-preview"
>
dev.to.
</a>
Let me show you how...
</p>
</div>
</body>
</html>
Next, it's necessary to have a card
element that will include and preview the information from the referred source:
<!--index.html-->
...
<div class="card">
<img src="" class="card-img-top">
<div class="card-body">
<h5 class="card-title"></h5>
<p class="card-text"></p>
</div>
</div>
So far, you see, that I useBootstrap 4
and custom CSS-classes for card styling. They should be imported to the <head />
too:
<!--index.html-->
...
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="index.css">
...
Thanks to Boostrap 4
functionality, element positioning, and some basic styles are applied automatically from the library. So, the index.css
file is not large, so below you find all needed styles for a link content previewer feature:
/*index.css*/
body {
font-size: 24px;
}
.wrapper {
width: 500px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
position: absolute;
}
.card {
width: 150px;
display: none;
font-size: 10px;
color: black;
position: absolute;
z-index: 100;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
}
.link-with-preview {
position: relative;
}
.card img {
width: 150px;
}
.card-title {
font-size: 14px;
}
To make a link content previewer work, we have to write JavaScript. I hope you haven't forgotten to add the script to the end of the body
in index.html
:
<!--index.html-->
...
<script src="index.js"></script>
And ready to start coding in JavaScript:
const card = document.querySelector(".card");
const hideLinkPreview = () => {
return card.style.display = 'none';
};
const showLinkPreview = event => {
const image = event.currentTarget.getAttribute("data-image");
card.querySelector('img').setAttribute("src", image);
const title = event.currentTarget.getAttribute("data-title");
card.querySelector('h5').textContent = title;
const text = event.currentTarget.getAttribute("data-text");
card.querySelector('p').textContent = text;
event.currentTarget.appendChild(card);
return card.style.display = 'inline-block';
};
document.querySelectorAll(".link-with-preview").forEach(el => {
el.addEventListener("mouseover", showLinkPreview);
el.addEventListener("mouseleave", hideLinkPreview)
});
Declare the
card
and implement two functionshideLinkPreview(event)
andshowLinkPreview(event)
with theevent
parameter. In our case, it'sonmouseover
andonmouse leave
events for the<a />
link.hideLinkPreview(event)
works easy. It just hides the content preview (a card) on a mouse leave event.For
showLinkPreview(event)
, it's important to get attributes likedata-image
,data-title
anddata-text
from the<a />
link, set them with to thecard
instance to show and preview the content of the referred resource on mouseover event.event.currentTarget.appendChild(card);
helps us to append thecard
inside the link content previewer and position/center the card properly above the link.Pass all the needed data to
index.html
to preview not-emptycard
in your browser on hover:
<!--index.html-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Link Content Previewer</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="wrapper">
<p>Hi there! π</p>
<p>I would like to share some frontend tips and tricks that
I have already applied to some of my projects.</p>
<p>Happily coming back with <br/> my
<a href="https://dev.to/ilonacodes/frontend-shorts-vue-js-vanilla-js-digital-dices-og"
onmouseover="showLinkPreview()"
onmouseleave="hideLinkPreview()"
class="link-with-preview"
data-image="https://dev-to-uploads.s3.amazonaws.com/i/3zp478dfafzy1mgfaevn.jpg"
data-title="Frontend Shorts: Vue.js + Vanilla.js β Digital Dices"
data-text="Let me show you how you can implement a dice-rolling simulator in less than 30 minutes of your time on the front-end."
>frontend shorts</a>
series on
<a href="https://dev.to"
onmouseover="showLinkPreview()"
onmouseleave="hideLinkPreview()"
class="link-with-preview"
data-image="https://thepracticaldev.s3.amazonaws.com/i/6hqmcjaxbgbon8ydw93z.png"
data-title="DEV Community π©βπ»π¨βπ»"
data-text="Where programmers share ideas and help each other growβA constructive and inclusive social network."
>
dev.to.
</a>
Let me show you how...
</p>
</div>
<div class="card">
<img src="" class="card-img-top">
<div class="card-body">
<h5 class="card-title"></h5>
<p class="card-text"></p>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
The full source code of the VanillaJS implementation you can find:
Part II: Link content previewer with Vue.js
As you guess so far, index.html
and index.css
will look similar to the index.html
and index.css
from the VanillaJS implementation too:
<div id="app">
<div class="wrapper">
<p>Hi there! π</p>
<p>I would like to share some frontend tips and tricks that
I have already applied to some of my projects.</p>
<p>Happily coming back with <br/> my
<link-previewer
href="https://dev.to/ilonacodes/frontend-shorts-vue-js-vanilla-js-digital-dices-og"
text="frontend shorts"
preview-img="https://dev-to-uploads.s3.amazonaws.com/i/3zp478dfafzy1mgfaevn.jpg"
preview-title="Frontend Shorts: Vue.js + Vanilla.js β Digital Dices"
preview-text="Let me show you how you can implement a dice-rolling simulator in less than 30 minutes of your time on the front-end."
></link-previewer>
series on
<link-previewer
href="https://dev.to"
text="dev.to."
preview-img="https://thepracticaldev.s3.amazonaws.com/i/6hqmcjaxbgbon8ydw93z.png"
preview-title="DEV Community π©βπ»π¨βπ»"
preview-text="Where programmers share ideas and help each other growβA constructive and inclusive social network."
></link-previewer>
Let me show you how...
</p>
</div>
</div>
To use Vue.js framework, you need to add Vue.js script for that:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
According to the index.html
, we are still missing link-previewer
component with the corresponding props: href
, text
, previewTitle
, previewImg
andpreviewText
. Let's create the link-previewer
component with Vue.js in index.html
below:
...
<script>
Vue.component('link-previewer', {
props: ['href', 'text', 'previewTitle', 'previewImg', 'previewText'],
data() {
return {
shown: false
};
},
methods: {
show() {
this.shown = true;
},
hide() {
this.shown = false;
}
},
// this enables proper syntax highlighting and auto-completion in the IDE for the HTML code snippet below:
//language=HTML
template: `
<a v-bind:href="href"
v-on:mouseover="show"
v-on:mouseleave="hide"
class="link-with-preview"
>
{{ text }}
<div class="card"
v-bind:class="{'card-show': shown}">
<img v-bind:src="previewImg" alt=""
class="card-img-top">
<div class="card-body">
<h5 class="card-title">{{ previewTitle }}</h5>
<div class="card-text">
{{ previewText }}
</div>
</div>
</div>
</a>
`
});
const app = new Vue({
el: '#app'
});
</script>
The only data that changes the state of the 'link-previewer' component is
shown: false
indata()
That depends on call of
show()
andhide()
methodsIn the case of Vue.js implementation, the
card
component with its referred props will be built as atemplate
.The data is passing from the
link-previewer
to thecard
with the help of thev-bind
shorthand, and the events viav-on
.
The full solution with Vue.js, you can see here: Vue.js β index.html.
Part III: Link content previewer with React.js
The HTML-structure of the App.js
component is almost the same as index.html
for the VanillaJS implementation:
// App.js
import React from "react";
import "./styles.css";
import { LinkPreviewer } from "./LinkPreviewer";
export default function App() {
return (
<div className="App">
<div>
<p>Hi there! π</p>
<p>
I would like to share some frontend tips and tricks that I have
already applied to some of my projects.
</p>
<p>
Happily coming back with <br /> my
<LinkPreviewer
href="https://dev.to/ilonacodes/frontend-shorts-vue-js-vanilla-js-digital-dices-og"
image="https://thepracticaldev.s3.amazonaws.com/i/6hqmcjaxbgbon8ydw93z.png"
title="Frontend Shorts: Vue.js + Vanilla.js β Digital Dices"
text="Let me show you how you can implement a dice-rolling simulator in less than 30 minutes of your time on the front-end."
>
frontend shorts
</LinkPreviewer>
series on
<LinkPreviewer
href="https://dev.to"
image="https://thepracticaldev.s3.amazonaws.com/i/6hqmcjaxbgbon8ydw93z.png"
title="DEV Community"
text="Where programmers share ideas and help each other growβA constructive and inclusive social network."
>
dev.to
</LinkPreviewer>
</p>
</div>
</div>
);
}
The difference is only that we need to create LinkPreviewer
component and use it to render the right data for link content previewing:
// LinkPreviewer
import React, { useState } from "react";
import "./styles.css";
export const LinkPreviewer = props => {
const [isShown, setIsShown] = useState(false);
return (
<a
href={props.href}
className="link-with-preview"
onMouseEnter={() => setIsShown(true)}
onMouseLeave={() => setIsShown(false)}
>
<span> {props.children} </span>
{isShown && (
<Card image={props.image} title={props.title} text={props.text} />
)}
</a>
);
};
const Card = props => {
return (
<div className="card">
<img src={props.image} className="card-img-top" alt="" />
<div className="card-body">
<h5 className="card-title">{props.title}</h5>
<p className="card-text">{props.text}</p>
</div>
</div>
);
};
The
LinkPreviewer
will return<a/>
with the needed properties, events and styling class to render the content previewing feature properly in the browser.The
Card
component renders content like image, title, and text of the referred source in preview whenisShown
is true.Thanks to React hook
const [isShown, setIsShown] = useState(false);
it's easy to handle two eventsonMouseEnter
andonMouseLeave
ofLinkPreviewer
on hover to hide and show the link content previewer.`
The CSS-classes are identical to the index.css
of the VanillaJS approach.
The code snippets with the React implementation are here.
π¬ Conclusion
As you can see, creating a link content previewer feature is easy, not depending on which JavaScript framework or library you are going to use for it. Because any implementation will not be that much different from another. The approach stays the same.
If you are a developer or a tech-savvy person who has their own blog, then you will not need to rely on a third-party library to have this kind of functionality. You can develop it on your own.
Thank you for reading!
I hope you found this frontend short useful and practical and would help me to spread it on the Internet, for example, via Twitter.
Code your best,
Ilona Codes.
Photo by Matteo Catanese on Unsplash
Top comments (9)
I guess getting images still need to be done manually, as getting
dev.to
image from your site will have to bypass CORS (still do-able with cors-anywhere.herokuapp.com)The library for scraping is provided by Mozilla, here -- github.com/mozilla/page-metadata-p...
It is somewhat in my solution, here -- dev.to/patarapolw/is-there-a-tool-...
It seems that I have just found the PROPER REST service -- github.com/mozilla/page-metadata-s...
Interesting, thanks for sharing these projects. I just published an addition to Ilona's post here on dev.to that renders the preview card content at runtime, using a small backend service.
It's built with Svelte / Sapper, but the Mozilla service looks very compelling.
This is a great post, thank you for sharing your approach Ilona.
It inspired me to write a Svelte / Sapper version that loads the preview card content dynamically at runtime. It let's me define the link with:
More details and a link to a GitHub repo at dev.to/mikenikles/a-link-content-p...
This is fantastic, thank you :)
Thank you for reading!
Very cool for the UX: bookmarked!
I hope this post will be helpful to you in the future! π
It's a nice approach. I always wondered how this thing works. Thank you
My pleasure, glad to help!