231

So is this the only way to render raw html with reactjs?

// http://facebook.github.io/react/docs/tutorial.html
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
      </div>
    );
  }
});

I know there are some cool ways to markup stuff with JSX, but I am mainly interested in being able to render raw html (with all the classes, inline styles, etc..). Something complicated like this:

<!-- http://getbootstrap.com/components/#dropdowns-example -->
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>

I would not want to have to rewrite all of that in JSX.

Maybe I am thinking about this all wrong. Please correct me.

Al.G.
  • 4,175
  • 6
  • 34
  • 55
vinhboy
  • 7,889
  • 7
  • 32
  • 44
  • 1
    That is nearly JSX. If you render a lot of markup as raw HTML, you're losing the benefit of using a library like React. I'd recommend doing the small changes (like "class" -> "className") to let React handle the elements. – Ross Allen Jan 14 '15 at 06:03
  • 2
    For this specific example someone has [already done the work for you](http://react-bootstrap.github.io/components.html#btn-dropdowns), however the question still stands for the general case. – Randy Morris Jan 14 '15 at 12:07
  • https://medium.com/@to_pe/how-to-add-react-to-a-simple-html-file-a11511c0235f – TechDog Nov 23 '17 at 16:04
  • HTML to JSX convert: https://transform.tools/html-to-jsx – Lazor Feb 22 '21 at 23:12

10 Answers10

229

There are now safer methods to render HTML. I covered this in a previous answer here. You have 4 options, the last uses dangerouslySetInnerHTML.

Methods for rendering HTML

  1. Easiest - Use Unicode, save the file as UTF-8 and set the charset to UTF-8.

    <div>{'First · Second'}</div>

  2. Safer - Use the Unicode number for the entity inside a Javascript string.

    <div>{'First \u00b7 Second'}</div>

    or

    <div>{'First ' + String.fromCharCode(183) + ' Second'}</div>

  3. Or a mixed array with strings and JSX elements.

    <div>{['First ', <span>&middot;</span>, ' Second']}</div>

  4. Last Resort - Insert raw HTML using dangerouslySetInnerHTML.

    <div dangerouslySetInnerHTML={{__html: 'First &middot; Second'}} />

Community
  • 1
  • 1
Brett DeWoody
  • 55,478
  • 28
  • 131
  • 182
  • wondering what other attributes receives `dangerouslySetInnerHTML` besides __html – Juan Solano Apr 12 '19 at 16:25
  • 1
    @JuanSolano none, according to the auto complete entries in a TypeScript environment. – Andreas Linnert Feb 17 '20 at 12:44
  • In a similar question, https://stackoverflow.com/questions/19266197/reactjs-convert-html-string-to-jsx/27938353#27938353, this answer didn't do too good. Maybe it's a better fit for this question or maybe people aren't reading the answer... :D – 425nesp May 18 '20 at 01:45
  • 2
    People get way to bent out of shape regarding dangerousSetInnerHtml. While devs should understand how it *potentially* is a vector for XSS attacks, there are valid use cases where this is the reasonable pragmatic approach, particularly in cases where the html you are setting isn't formed from user input or is formed from sanitized user input. If you know the HTML and have a reason to store it in a variable or something, this is by far the most elegant method. – hurlbz May 08 '21 at 00:24
69

You could leverage the html-to-react npm module.

Note: I'm the author of the module and just published it a few hours ago. Please feel free to report any bugs or usability issues.

Mike Nikles
  • 1,320
  • 10
  • 16
64

dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.

It is better/safer to sanitise your raw HTML (using e.g., DOMPurify) before injecting it into the DOM via dangerouslySetInnerHTML.

DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks.

Example:

import React from 'react'
import createDOMPurify from 'dompurify'
import { JSDOM } from 'jsdom'

const window = (new JSDOM('')).window
const DOMPurify = createDOMPurify(window)

const rawHTML = `
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>
`

const YourComponent = () => (
  <div>
    { <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(rawHTML) }} /> }
  </div>
)

export default YourComponent
Yuci
  • 22,858
  • 8
  • 99
  • 108
37

I have used this in quick and dirty situations:

// react render method:

render() {
    return (
      <div>
        { this.props.textOrHtml.indexOf('</') !== -1
            ? (
                <div dangerouslySetInnerHTML={{__html: this.props.textOrHtml.replace(/(<? *script)/gi, 'illegalscript')}} >
                </div>
              )
            : this.props.textOrHtml
          }

      </div>
      )
  }
Al.G.
  • 4,175
  • 6
  • 34
  • 55
Cory Robinson
  • 3,979
  • 4
  • 34
  • 48
22

I have tried this pure component:

const RawHTML = ({children, className = ""}) => 
<div className={className}
  dangerouslySetInnerHTML={{ __html: children.replace(/\n/g, '<br />')}} />

Features

  • Takes classNameprop (easier to style it)
  • Replaces \n to <br /> (you often want to do that)
  • Place content as children when using the component like:
  • <RawHTML>{myHTML}</RawHTML>

I have placed the component in a Gist at Github: RawHTML: ReactJS pure component to render HTML

Netsi1964
  • 2,857
  • 1
  • 23
  • 17
13
export class ModalBody extends Component{
    rawMarkup(){
        var rawMarkup = this.props.content
        return { __html: rawMarkup };
    }
    render(){
        return(
                <div className="modal-body">
                     <span dangerouslySetInnerHTML={this.rawMarkup()} />

                </div>
            )
    }
}
Jozcar
  • 916
  • 9
  • 11
  • The above work for me, I was passing html to modal body. – Jozcar Mar 18 '17 at 02:46
  • It won't work if you have anchor tags with hashes for internal anchors, so far i have NO solutions to bring in html with internal anchors that work as internal hashtag anchors, the anchor want to re-render the page to no where – Eric Clarke Oct 19 '20 at 12:59
9

I used this library called Parser. It worked for what I needed.

import React, { Component } from 'react';    
import Parser from 'html-react-parser';

class MyComponent extends Component {
  render() {
    <div>{Parser(this.state.message)}</div>
  }
};
ecairol
  • 5,794
  • 1
  • 25
  • 21
6

dangerouslySetInnerHTML should not be used unless absolutely necessary. According to the docs, "This is mainly for cooperating with DOM string manipulation libraries". When you use it, you're giving up the benefit of React's DOM management.

In your case, it is pretty straightforward to convert to valid JSX syntax; just change class attributes to className. Or, as mentioned in the comments above, you can use the ReactBootstrap library which encapsulates Bootstrap elements into React components.

Bondolin
  • 2,536
  • 6
  • 30
  • 59
Breno Ferreira
  • 1,196
  • 9
  • 8
  • 8
    Thanks for your answer. I understand the security implications of using innerHTML and I know I can convert it to JSX. But I am specifically asking about React's support for using raw HTML snippets. – vinhboy Jan 14 '15 at 18:21
  • What exactly do you mean by "React's support for using raw HTML snippets"? – Breno Ferreira Jan 15 '15 at 00:18
  • I've no other choice than to using "dangerouslySetInnerHTML"!!! – Zia Ullah Dec 28 '21 at 19:00
3

Here's a little less opinionated version of the RawHTML function posted before. It lets you:

  • configure the tag
  • optionally replace newlines to <br />'s
  • pass extra props that RawHTML will pass to the created element
  • supply an empty string (RawHTML></RawHTML>)

Here's the component:

const RawHTML = ({ children, tag = 'div', nl2br = true, ...rest }) =>
    React.createElement(tag, {
        dangerouslySetInnerHTML: {
            __html: nl2br
                ? children && children.replace(/\n/g, '<br />')
                : children,
        },
        ...rest,
    });
RawHTML.propTypes = {
    children: PropTypes.string,
    nl2br: PropTypes.bool,
    tag: PropTypes.string,
};

Usage:

<RawHTML>{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2">{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2" className="test">{'First &middot; Second'}</RawHTML>
<RawHTML>{'first line\nsecond line'}</RawHTML>
<RawHTML nl2br={false}>{'first line\nsecond line'}</RawHTML>
<RawHTML></RawHTML>

Output:

<div>First · Second</div>
<h2>First · Second</h2>
<h2 class="test">First · Second</h2>
<div>first line<br>second line</div>
<div>first line
second line</div>
<div></div>

It will break on:

<RawHTML><h1>First &middot; Second</h1></RawHTML>
Christiaan Westerbeek
  • 9,774
  • 13
  • 60
  • 82
2

I needed to use a link with onLoad attribute in my head where div is not allowed so this caused me significant pain. My current workaround is to close the original script tag, do what I need to do, then open script tag (to be closed by the original). Hope this might help someone who has absolutely no other choice:

<script dangerouslySetInnerHTML={{ __html: `</script>
   <link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans" as="style" onLoad="this.onload=null;this.rel='stylesheet'" crossOrigin="anonymous"/>
<script>`,}}/>
Adam Lane
  • 1,634
  • 19
  • 23