DEV Community

Cover image for Frontend Shorts: How to create link content previewer with React, Vue, and Vanilla JavaScript
Ilona Codes
Ilona Codes

Posted on

Frontend Shorts: How to create link content previewer with React, Vue, and Vanilla JavaScript

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.

Link Content Previewer

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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">
...
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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)
});
Enter fullscreen mode Exit fullscreen mode
  1. Declare thecard and implement two functions hideLinkPreview(event) and showLinkPreview(event) with the event parameter. In our case, it's onmouseover and onmouse leave events for the <a /> link.

  2. hideLinkPreview(event) works easy. It just hides the content preview (a card) on a mouse leave event.

  3. For showLinkPreview(event), it's important to get attributes like data-image, data-title and data-text from the <a /> link, set them with to the card instance to show and preview the content of the referred resource on mouseover event.

  4. event.currentTarget.appendChild(card); helps us to append the card inside the link content previewer and position/center the card properly above the link.

  5. Pass all the needed data to index.html to preview not-empty card 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>
Enter fullscreen mode Exit fullscreen mode

The full source code of the VanillaJS implementation you can find:

VanillaJS β€” index.html

VanillaJS β€” index.css

VanillaJS β€” index.js

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
  • The only data that changes the state of the 'link-previewer' component is shown: false in data()

  • That depends on call of show() and hide() methods

  • In the case of Vue.js implementation, the card component with its referred props will be built as a template.

  • The data is passing from the link-previewer to the card with the help of the v-bind shorthand, and the events via v-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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode
  • 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 when isShown is true.

  • Thanks to React hook const [isShown, setIsShown] = useState(false); it's easy to handle two events onMouseEnter and onMouseLeave of LinkPrevieweron 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)

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited

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...

Collapse
 
mikenikles profile image
Mike

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.

Collapse
 
mikenikles profile image
Mike

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:

<LinkPreview href="https://dev.to">dev.to</LinkPreview>

More details and a link to a GitHub repo at dev.to/mikenikles/a-link-content-p...

Collapse
 
netluxe profile image
Netluxe

This is fantastic, thank you :)

Collapse
 
ilonacodes profile image
Ilona Codes

Thank you for reading!

Collapse
 
anwar_nairi profile image
Anwar

Very cool for the UX: bookmarked!

Collapse
 
ilonacodes profile image
Ilona Codes

I hope this post will be helpful to you in the future! πŸ™‚

Collapse
 
monfernape profile image
Usman Khalil

It's a nice approach. I always wondered how this thing works. Thank you

Collapse
 
ilonacodes profile image
Ilona Codes

My pleasure, glad to help!