4

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

Rolando Urquiza
  • 1,404
  • 3
  • 17
  • 29

1 Answers1

6

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

Ana Liza Pandac
  • 4,795
  • 2
  • 24
  • 36
  • 1
    I saw the issue you mentioned, and what you say about XSS attacks is the reason I didn't adopt that solution. Nevertheless, if not best solution appears, I guess I will have to adopt it and use [dompurify](https://github.com/cure53/DOMPurify) to prevent XSS attacks. – Rolando Urquiza Jan 14 '19 at 16:25