295

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.

5
  • 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. Commented Jan 14, 2015 at 6:03
  • 2
    For this specific example someone has already done the work for you, however the question still stands for the general case. Commented Jan 14, 2015 at 12:07
  • medium.com/@to_pe/… Commented Nov 23, 2017 at 16:04
  • HTML to JSX convert: transform.tools/html-to-jsx Commented Feb 22, 2021 at 23:12
  • I am working on a Next.js application where the goal is to fetch analytics and marketing scripts — specifically GTM, Amplitude, and VWO — from the CMS as text/HTML snippets. These snippets typically include <script> and <link> tags. I want to render these scripts in the UI without wrapping them in any extra elements such as <div>, <span>, or <p> in the <head> section. Does anyone have suggestions on how to achieve this? Commented Aug 13 at 22:19

14 Answers 14

278

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'}} />

Sign up to request clarification or add additional context in comments.

5 Comments

wondering what other attributes receives dangerouslySetInnerHTML besides __html
@JuanSolano none, according to the auto complete entries in a TypeScript environment.
In a similar question, stackoverflow.com/questions/19266197/…, 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
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.
I don't understand how your answer answers the question! The user wants to render some HTML imported from somewhere dynamically, where in 1, 2, or 3 did you answer that question?
102

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

1 Comment

I've used this without JSDOM. It worked like a charm. Thank you! Reading this thread I've realized how exposed to XSS attacks could a Web App with a CMS given to non-technical people.
81

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.

8 Comments

does it use dangerouslySetInnerHTML internally ?
I just checked the code. It doesn't seem to be using dangerouslySetInnerHTML.
Mike are you still actively maintaining this npm module?
Hey Daniel, I don't and one of the contributors took it over and published the last release 7 months ago. See github.com/aknuds1/html-to-react
this is bloated and uses ramda etc and large libs - I do not recommend
|
42

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>
      )
  }

2 Comments

This is not safe - what if the HTML contains <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert('test');">?
It's safe if you're in control of the HTML being rendered
25

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

Comments

15
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>
            )
    }
}

2 Comments

The above work for me, I was passing html to modal body.
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
12

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>
  }
};

2 Comments

21KB (8KB gzipped). I couldn't justify that for browser code.
this library breaks my Expo app
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.

3 Comments

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.
What exactly do you mean by "React's support for using raw HTML snippets"?
I've no other choice than to using "dangerouslySetInnerHTML"!!!
5

Here is a solution the boils down to two steps:

  1. Use built-in APIs to parse a raw HTML string into an HTML Element
  2. Recursively transform an Element object (and its children) into ReactElement objects.

Note: this is a good example for learning. But consider the options described in the other answers, like the html-to-react library.

Characteristics of this solution:


Here is the .jsx code:

// RawHtmlToReactExample.jsx
import React from "react";

/**
 * Turn a raw string representing HTML code into an HTML 'Element' object.
 *
 * This uses the technique described by this StackOverflow answer: https://stackoverflow.com/a/35385518
 * Note: this only supports HTML that describes a single top-level element. See the linked post for more options.
 *
 * @param {String} rawHtml A raw string representing HTML code
 * @return {Element} an HTML element
 */
function htmlStringToElement(rawHtml) {
    const template = document.createElement('template');
    rawHtml = rawHtml.trim();
    template.innerHTML = rawHtml;
    return template.content.firstChild;
}

/**
 * Turn an HTML element into a React element.
 *
 * This uses a recursive algorithm. For illustrative purposes it logs to the console.
 *
 * @param {Element} el
 * @return {ReactElement} (or a string in the case of text nodes?)
 */
function elementToReact(el) {
    const tagName = el.tagName?.toLowerCase(); // Note: 'React.createElement' prefers lowercase tag names for HTML elements.
    const descriptor = tagName ?? el.nodeName;
    const childNodes = Array.from(el.childNodes);
    if (childNodes.length > 0) {
        console.log(`This element ('${descriptor}') has child nodes. Let's transform them now.`);
        const childReactElements = childNodes.map(childNode => elementToReact(childNode)).filter(el => {
            // In the edge case that we found an unsupported node type, we'll just filter it out.
            return el !== null
        });
        return React.createElement(tagName, null, ...childReactElements);
    } else {
        // This is a "bottom out" point. The recursion stops here. The element is either a text node, a comment node,
        // and maybe some other types. I'm not totally sure. Reference the docs to understand the different node
        // types: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
        console.log(`This element ('${descriptor}') has no child nodes.`);

        // For simplicity, let's only support text nodes.
        const nodeType = el.nodeType;
        if (nodeType === Node.TEXT_NODE) {
            return el.textContent;
        } else {
            console.warn(`Unsupported node type: ${nodeType}. Consider improving this function to support this type`);
            return null;
        }
    }
}

export function RawHtmlToReactExample() {
    const myRawHtml = `<p>This is <em>raw</em> HTML with some nested tags. Let's incorporate it into a React element.`;
    const myElement = htmlStringToElement(myRawHtml);
    const myReactElement = elementToReact(myElement);

    return (<>
        <h1>Incorporate Raw HTML into React</h1>

        {/* Technique #1: Use React's 'dangerouslySetInnerHTML' attribute */}
        <div dangerouslySetInnerHTML={{__html: myRawHtml}}></div>

        {/* Technique #2: Use a recursive algorithm to turn an HTML element into a React element */}
        {myReactElement}
    </>)
}

2 Comments

const descriptor = tagName ?? el.nodeName; what does this line mean?
Good question, that statement is only helpful for the debug console logging that happens in later lines. That line gets a "human readable descriptor" of the el object. Sometimes, el is an HTML element and it has a tag name (for example, a, div, li) but sometimes el is a TextNode. TextNode's do not have a tag name but they do have a node name. The ?? operator is this developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
4

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>

Comments

3

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>`,}}/>

Comments

2

This works for me:

    render()
    {
        var buff = '';
        for(var k=0; k<10; k++)
        {
            buff += "<span> " + k + " </span>";
        }

        return (
            <div className='pagger'>               
                  <div className='pleft'>
                     <div dangerouslySetInnerHTML={{__html: buff }} />
                  </div>
                  <div className='pright'>
                         <div className='records'>10</div>
                         <div className='records'>50</div>
                         <div className='records records_selected'>100</div>
                         <div className='records'>1000</div>
                     </div>
            </div>
        )
    }

Comments

1

It is safer to sanitize the raw html with something like DOMPurify then use with dangerouslySetInnerHTML

npm i dompurify

For types

npm i --save-dev @types/dompurify

import React from 'react'
import * as DOMPurify from 'dompurify';

let dirty = '<b>hello there</b>';
let clean = DOMPurify.sanitize(dirty);

function MyComponent() {
  return <div dangerouslySetInnerHTML={{ __html: clean) }} />;
}

If you have problems making it work in your specific setup, consider looking at the amazing isomorphic-dompurify project which solves lots of problems people might run into.

npm i isomorphic-dompurify

import React from 'react'
import DOMPurify from 'isomorphic-dompurify';

const dirty = '<p>hello</p>'
const clean = DOMPurify.sanitize(dirty);

function MyComponent() {
    return <div dangerouslySetInnerHTML={{ __html: clean) }} />;
}

For Demo https://cure53.de/purify

For More https://github.com/cure53/DOMPurify

https://github.com/kkomelin/isomorphic-dompurify

3 Comments

"Run code snippet" fails: i.imgur.com/fYYy4jH.png
The second "Run code snippet" also fails: i.imgur.com/HVUyl7t.png
"{{ __html: clean) }}" I think that ")" is in error.
-2

the easy way use you can use dangerouslySetInnerHTML

<p dangerouslySetInnerHTML={{ __html: "your html" }}>
</p>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.