0

I have a html string that contains a link. I need to add the attribute rel="noopener" for security purposes. The html string is injected through dangerouslySetInnerHtml:

const Component = ({ message }) => {
  return (
    <div>
      <div dangerouslySetInnerHTML={{ __html: message }} />
    <div>
  );
};

The string looks like: Hello check out <a href="https://my-link.com" target="_blank">this page</a>

So the desired output would be: Hello check out <a href="https://my-link.com" target="_blank" rel="noopener">this page</a>

How to do it?

2
  • Please post the code you use right now.. And what's stopping you from writing this html element explicitly (I mean, if it's not dynamic)? Commented May 4, 2021 at 9:04
  • Hi, I've updated the original post. But it's just a simple setDangerousInnerHtml div. I receive the html from an api to which I do not have access. Commented May 4, 2021 at 9:11

4 Answers 4

2

Try this:

const Component = ({ message }) => {

    function secureATags(html) {
        // Parse HTML
        let doc = (new DOMParser()).parseFromString(html, "text/html")
        // Append attribute
        doc.querySelectorAll('a').forEach(entry => {
            entry.setAttribute('rel', 'noopener')
        })

        // Reserialize to HTML
        return doc.body.innerHTML
    }

    return (
        <div>
            <div dangerouslySetInnerHTML={{ __html: secureATags(message) }} />
        <div>
    )
}
Sign up to request clarification or add additional context in comments.

Comments

0

I would use the Browser DOM to achieve this, as follows:

const div = document.createElement("div");

div.innerHTML = 'Hello check out <a href="https://my-link.com" target="_blank">this page</a>';
div.childNodes[1].setAttribute("rel", "noopener");

console.log(div.innerHTML);

If the actual HTML text is more complex than in your example, then div.childNodes[1] will need to be replaced with code that looks for and selects the proper node. But even then (or especially then?), this is probably the easiest and most reliable way to achieve your goal.

Comments

0

Direct use of setDangerousInnerHtml is strictly not recommended due to security issues. you can use a plugin on npmjs.org pkgname: React-html-parser for injecting the html safely

Comments

0

Maybe consider using a function or component that puts it all together based on the data you send in? E.g.

function App() {
  const linkBuilder = (textBefore, linkText, textAfter, href) => {
    return (
      <div>
        {textBefore}
        <a href={href} target="_blank">
          {linkText}
        </a>
        {textAfter}
      </div>
    );
  };
  return (
    <div>
      {linkBuilder("Hello check out ", "this page", "", "www.google.com")}
    </div>
  );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Also according to this you don't need rel=noopener anymore if you use target="_blank". But if it's necessary you can pass it in as a boolean and apply it on the function/component side.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.