Creating Dynamic Hyperlinked Text Components in VUE JS

Introduction

When building modern web applications, there are many instances where you need to dynamically insert hyperlinks into a block of text. Whether you’re parsing user-generated content or just want to ensure all URLs in a given string are clickable, having a reusable component to handle this task efficiently is crucial. In this blog post, we'll walk through how to create a dynamic Vue.js component that automatically detects and transforms URLs in a string into clickable hyperlinks. This component will also handle text formatting, like adding line breaks, to ensure the content displays as expected.

Why Dynamic Hyperlinking?

Imagine you have a text string that includes URLs. Without the right component, you’d need to manually find and wrap each URL in an <a> tag. This can be error-prone, especially when dealing with large blocks of text or user-generated content. A dynamic hyperlinking component simplifies this process by automatically detecting URLs and converting them into clickable links, which enhances user experience and ensures consistency.

The Code Explained

Let's break down the code to understand how this component works and why it's beneficial.

import { h } from "vue"

export default {
    props: {
        tag: {
            type: String,
            required: true,
            default: "p",
        },
        text: {
            type: String,
            default: null,
        },
        className: {
            type: [String, Array],
            required: false,
            default: "",
        },
        hyperLinkClass: {
            type: [String, Array],
            required: false,
            default: "",
        },
    },
    setup(props) {
        const addHttps = (url) => {
            return url.startsWith("http://") || url.startsWith("https://")
                ? url
                : `https://${url.startsWith("www.") ? "" : "www."}${url}`
        }

        const urlRegex = /\b(?:https?:\/\/|www\.)\S+\b/gi

        const processText = (text) => {
            const parts = []
            let lastIndex = 0
            let match

            while ((match = urlRegex.exec(text)) !== null) {
                if (lastIndex < match.index) {
                    parts.push(text.slice(lastIndex, match.index))
                }
                parts.push(h("a", {
                    href: addHttps(match[0]),
                    target: "_blank",
                    class: props.hyperLinkClass,
                }, match[0]))
                lastIndex = urlRegex.lastIndex
            }

            if (lastIndex < text.length) {
                parts.push(text.slice(lastIndex))
            }

            return parts
        }

        const lines = props.text ? props?.text?.split("\n") : []
        const children = lines.reduce((accumulator, line, index) => {
            const lineElements = processText(line)

            if (index > 0) {
                accumulator.push(h("br"))
            }

            return accumulator.concat(lineElements)
        }, [])

        return () => h(
            props?.tag,
            {
                class: props?.className,
            },
            children,
        )
    },
}
Component Structure
  • Props Configuration:

    • tag: Defines the HTML tag (like p, div, or span) that will wrap the content. This adds flexibility, allowing the component to be used in various contexts.

    • text: The string containing the text that may include URLs. This will be processed to identify and link the URLs.

    • className: This allows passing custom classes to style the component as needed.

    • hyperLinkClass: Defines the class to style the generated hyperlinks. By default, it ensures the links are visually consistent with the rest of the design.

Core Functionality:
  • addHttps Function: This function ensures that all URLs start with https:// or http://. If a URL lacks these protocols, https:// is prepended. This guarantees that all links are valid and clickable.

  • urlRegex: A regular expression regex is used to detect URLs in the text. The regex identifies strings that start with "http://", "https://", or "www." and treats them as URLs.

  • processText Function: This is where the magic happens. It splits the input text into chunks, identifies URLs, wraps them in <a> tags, and returns the processed content. This function is robust enough to handle multiple URLs within the same text.

  • Lines Processing: The text is split into lines to preserve any line breaks. Each line is processed individually to find and wrap URLs, ensuring that the formatting remains intact.

  • Dynamic Rendering: The component dynamically renders the processed text within the specified HTML tag, applying the relevant styles.

How to Use the Component

Once you’ve set up this component, you can easily use it in your Vue.js application:

<HyperlinkedText 
    tag="p" 
    :text="`Check out this website: www.example.com and also this one: https://www.another-example.com`" 
    className="my-custom-class" 
    hyperLinkClass="custom-link-class" 
/>

This will render a paragraph where the URLs are automatically hyperlinked and styled with your custom classes.

Benefits

  • Efficiency: Automatically finds and hyperlinks URLs without manual intervention.

  • Flexibility: Use any HTML tag and customize the styles as needed.

  • User Experience: Enhances the readability and interactivity of text, ensuring users can easily click on links.

Conclusion

This dynamic hyperlinking component is a powerful tool for any Vue.js developer. By automatically detecting and linking URLs, it saves time and ensures consistency across your application. Whether you’re handling user-generated content or simply want to streamline your content management process, this component is a valuable addition to your toolkit.

With this component in place, you can confidently manage text with embedded links, providing a seamless and user-friendly experience.

Feel free to share your thoughts and opinions and leave me a comment if you have any problems or questions. 😎😎

I hope you liked it and learned something!

Happy Coding!!

1
Subscribe to my newsletter

Read articles from Sailesh Shrestha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sailesh Shrestha
Sailesh Shrestha