JayCodist
JayCodist

Reputation: 2554

How to open some child links in new tab in React

I have a page built with React (NextJS) and I am pulling some markup string content from Wordpress and inserting it into my JSX, like so:

...
<div className="wrapper">
  <p
     className="text-content"
     dangerouslySetInnerHTML={{ __html: post.content.rendered }}
  ></p>
</div>
...

Now, the markup possibly contains links and I want to open all those links on new tab. So I tried:

...
<div className="wrapper">
  <base target="_blank" />
  <p
     className="text-content"
     dangerouslySetInnerHTML={{ __html: post.content.rendered }}
  ></p>
</div>
...

and all links in the markup are opened on new tab so, great. But the problem is that all other links in the page including those outside the div.wrapper element are opened in new tabs (since <base /> is scoped to the entire page) and I'll like to prevent this.

Since I can't use multiple <base /> on the same page, the other option I'm aware of is to loop through anchor tags of interest with document.querySelector(".wrapper a") and add the target attribute to all of them but, in React it's an anti-pattern to modify the DOM directly.

So I'm not sure how best to proceed. What do I do?

Upvotes: 3

Views: 1262

Answers (2)

ehab
ehab

Reputation: 8064

Well first of all base element should only be inserted in html head element, and not inside the body html element, you could do that imperatively or using the react-helmet library - if you still need to use it.

dangerouslySetInnerHTML is in itself an imperative pice of code, but sometimes its the only possible solutions for a certain use cases, now regarding the links you could either do it using imperative code in a useEffect or componentDidMount, or you code use react-html-parser which will enable you to modify dom elements in a more declarative fashion - i say in a more declarative fashion because while its a react component in practice its still more imperative than its declarative in nature, but still better than custom code running in useEffect or componentDidMount

Upvotes: 1

Veljko Blagojevic
Veljko Blagojevic

Reputation: 427

You can use DOMParser API to achieve that.

Here's a little snippet

const parser = new DOMParser();
const htmlText = `<div><a href="#some-url">Url link</a></div>`;

let content = parser.parseFromString(htmlText, "text/html");
const anchors = content.getElementsByTagName('a');

Array.from(anchors).forEach(a => { 
    a.setAttribute("target", "_blank");
})


console.log(content.body.innerHTML); // Here it is your new string

The code may need to be improved a bit, I've just typed this out of MDN example and I didn't have time to test it. Does this work?

Upvotes: 6

Related Questions