227
votes

Here's what I tried and how it goes wrong.

This works:

<div dangerouslySetInnerHTML={{ __html: "<h1>Hi there!</h1>" }} />

This doesn't:

<div dangerouslySetInnerHTML={{ __html: this.props.match.description }} />

The description property is just a normal string of HTML content. However it's rendered as a string, not as HTML for some reason.

enter image description here

Any suggestions?

13

13 Answers

69
votes

Check if the text you're trying to append to the node is not escaped like this:

var prop = {
    match: {
        description: '&lt;h1&gt;Hi there!&lt;/h1&gt;'
    }
};

Instead of this:

var prop = {
    match: {
        description: '<h1>Hi there!</h1>'
    }
};

if is escaped you should convert it from your server-side.

The node is text because is escaped

The node is text because is escaped

The node is a dom node because isn't escaped

The node is a dom node because isn't escaped

161
votes

Is this.props.match.description a string or an object? If it's a string, it should be converted to HTML just fine. Example:

class App extends React.Component {

constructor() {
    super();
    this.state = {
      description: '<h1 style="color:red;">something</h1>'
    }
  }
  
  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.description }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

Result: http://codepen.io/ilanus/pen/QKgoLA?editors=1011

However if description is <h1 style="color:red;">something</h1> without the quotes '', you're going to get:

​Object {
$$typeof: [object Symbol] {},
  _owner: null,
  key: null,
  props: Object {
    children: "something",
    style: "color:red;"
  },
  ref: null,
  type: "h1"
}

If It's a string and you don't see any HTML markup the only problem I see is wrong markup..

UPDATE

If you are dealing with HTML Entities, You need to decode them before sending them to dangerouslySetInnerHTML that's why it's called "dangerously" :)

Working example:

class App extends React.Component {

  constructor() {
    super();
    this.state = {
      description: '&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;'
    }
  }

   htmlDecode(input){
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.htmlDecode(this.state.description) }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
99
votes

I use 'react-html-parser'

yarn add react-html-parser
import ReactHtmlParser from 'react-html-parser'; 

<div> { ReactHtmlParser (html_string) } </div>

Source on npmjs.com

Lifting up @okram's comment for more visibility:

from its github description: Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTML from npmjs.com A utility for converting HTML strings into React components. Avoids the use of dangerouslySetInnerHTML and converts standard HTML elements, attributes and inline styles into their React equivalents.

20
votes

If you have control over where the string containing html is coming from (ie. somewhere in your app), you can benefit from the new <Fragment> API, doing something like:

import React, {Fragment} from 'react'

const stringsSomeWithHtml = {
  testOne: (
    <Fragment>
      Some text <strong>wrapped with strong</strong>
    </Fragment>
  ),
  testTwo: `This is just a plain string, but it'll print fine too`,
}

...

render() {
  return <div>{stringsSomeWithHtml[prop.key]}</div>
}
9
votes

If you have HTML in a string, I would recommend using a package called html-react-parser.

Install it: npm install html-react-parser or if you use yarn, yarn add html-react-parser

Use it something like this

import parse from 'html-react-parser'
const yourHtmlString = '<h1>Hello</h1>'
<div>
    {parse(yourHtmlString)}
</div>

Reference: https://www.npmjs.com/package/html-react-parser

8
votes

You just use dangerouslySetInnerHTML method of React

<div dangerouslySetInnerHTML={{ __html: htmlString }} />

Or you can implement more with this easy way: Render the HTML raw in React app

6
votes

I use innerHTML together a ref to span:

import React, { useRef, useEffect, useState } from 'react';

export default function Sample() {
  const spanRef = useRef<HTMLSpanElement>(null);
  const [someHTML,] = useState("some <b>bold</b>");

  useEffect(() => {
    if (spanRef.current) {
      spanRef.current.innerHTML = someHTML;
    }
  }, [spanRef.current, someHTML]);

  return <div>
    my custom text follows<br />
    <span ref={spanRef} />
  </div>
}
4
votes

In my case, I used react-render-html

First install the package by npm i --save react-render-html

then,

import renderHTML from 'react-render-html';

renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")
1
votes

I could not get npm build to work with react-html-parser. However, in my case, I was able to successfully make use of https://reactjs.org/docs/fragments.html. I had a requirement to show few html unicode characters , but they should not be directly embedded in the JSX. Within the JSX, it had to be picked from the Component's state. Component code snippet is given below :

constructor() 
{
this.state = {
      rankMap : {"5" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9733;</Fragment> , 
                 "4" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9734;</Fragment>, 
                 "3" : <Fragment>&#9733; &#9733; &#9733; &#9734; &#9734;</Fragment> , 
                 "2" : <Fragment>&#9733; &#9733; &#9734; &#9734; &#9734;</Fragment>, 
                 "1" : <Fragment>&#9733; &#9734; &#9734; &#9734; &#9734;</Fragment>}
                };
}

render() 
{
       return (<div class="card-footer">
                    <small class="text-muted">{ this.state.rankMap["5"] }</small>
               </div>);
}
0
votes

i use https://www.npmjs.com/package/html-to-react

const HtmlToReactParser = require('html-to-react').Parser;
let htmlInput = html.template;
let htmlToReactParser = new HtmlToReactParser();
let reactElement = htmlToReactParser.parse(htmlInput); 
return(<div>{reactElement}</div>)
0
votes

You can also use parseReactHTMLComponent from Jumper Package. Just look at it, it's easy and you don't need to use JSX syntax.

https://codesandbox.io/s/jumper-module-react-simple-parser-3b8c9?file=/src/App.js .

More on Jumper:

https://github.com/Grano22/jumper/blob/master/components.js

NPM Package:

https://www.npmjs.com/package/jumper_react

0
votes

As per @Hou Soune above,

<div dangerouslySetInnerHTML={{ __html: htmlString }} />

worked for me.

Parse string: '<p>Hello</p>' to element <p>Hello</p>

-2
votes

If you have control to the {this.props.match.description} and if you are using JSX. I would recommend not to use "dangerouslySetInnerHTML".

// In JSX, you can define a html object rather than a string to contain raw HTML
let description = <h1>Hi there!</h1>;

// Here is how you print
return (
    {description}
);