Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React dangerouslySetInnerHTML not working when using variable

I'm creating an SPA using React that searches data and displays results. Each result follows the following model

{
  "title": "A Title",
  "body": " <li>escaped html <strong>that sould be rendered</strong>.</li>
    </ul>"
}

The body property is always an escaped html that should be rendered in a component. This component looks like this:

Code

function SearchResult({ title, body, favourite }) {
  return (
    <article className="SearchResult">
    <section>
      <i className={`icon-star${favourite ? ' marked' : ''}`} />
      {title}
    </section>
    <section
      dangerouslySetInnerHTML={{ __html: body }}
      className="SearchResult-body"
    />
  </article>
  );
}

but the body of each result is not being rendered correctly, instead, it shows the html as a text enter image description here enter image description here

The issue is that it only happens when I create the component passing a variable to the body property

results.map((result, index) => (
      <SearchResult key={index} title={result.title} body={result.body} />
    ))

But if I do this, it works fine

<SearchResult
    title="A title"
    body=" &lt;li&gt;escaped html&amp;nbsp;&lt;strong&gt;that sould be rendered&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;"
  />

Why is this different? Is there any preprocessing that I should add to the value before passing it in the property that is added by default when I use the fixed value?

Demo

A demo of this issue can be seen here

like image 295
Rolando Urquiza Avatar asked Sep 17 '25 04:09

Rolando Urquiza


1 Answers

It seems like this issue only occurs when you give it an escaped html.

A solution implemented by @sergiotapia involves creating a helper function to unescape the html string to make it work.

htmlDecode(content) {
  let e = document.createElement('div');
  e.innerHTML = content;
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
<section
  dangerouslySetInnerHTML={{ __html: htmlDecode(body) }}
  className="SearchResult-body"
/>

However as @brigand mentioned and I'll quote "Unescaping it could allow for XSS attacks and incorrect rendering." so this might not be the perfect solution for this.

See working example

like image 133
Ana Liza Pandac Avatar answered Sep 18 '25 16:09

Ana Liza Pandac