1

I am currently working on a React project and I've encountered a challenge. I have a text response that I need to parse in such a way that any URLs in the text are converted to clickable hyperlinks ( tags). Additionally, I have a requirement where I need to highlight certain words within the text based on a provided search value.

This highlighted text isn't part of the URL, it could be anywhere within the text response.

For example, given this text: "Hello, check out https://www.example.com for more details. The example site is really useful."

If my search value was "example", I'd want to generate:

<span>
  Hello, check out <a href="https://www.example.com" target="_blank">https://www.example.com</a> for more 
  details. The <mark>example</mark> site is really useful.
</span>

Where "https://www.example.com" is a clickable hyperlink and "example" is highlighted.

Any suggestions on how to achieve this in React would be highly appreciated. Thank you!

1 Answers1

2

You could split() your sentence on a space, then map() over them;

  • If it matches your search pattern, wrap it in <mark>.

  • If it matches an url, wrap it in a <a>.
    I've used the regex to check for an url from this answer.

Then return the element, with a space at the end if it's not the last word.

The reason why we apply the space manually is because join() can't be used with an array holding React elements.

const { useState } = React;

const Example = () => {

    const validURL = (str) => {
        var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
        '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
        '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
        '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
        '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
        '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
        return !!pattern.test(str);
    }

    const search = "example";
    const raw = "Hello, check out https://www.example.com for more details. The example site is really useful.";
    const splitted = raw.split(' ');
    
    const parsed = splitted.map((p, i) => {
        let e = p;
        if (p === search) {
            e = <mark>{p}</mark>
        } else if (validURL(p)) {
            e = <a href={p} target="_blank">{p}</a>;
        }
        return <React.Fragment>{e}{(i === splitted.length) ? '' : ' '}</React.Fragment>;
    });

    return (
        <div>
            <h1>{'Example'}</h1>
            <em>{parsed}</em>
        </div>
    )
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
0stone0
  • 34,288
  • 4
  • 39
  • 64