How to Parse Html to React Component?

This is my senario :
1. Application request CMS(Content management system) for page contents.
2. CMS return "<div>Hi,<SpecialButton color="red">My Button</SpecialButton></div>"
3. Application consume the content, render corresponding component with data provided in attribute.

I can't figure out how to do step 3 in React way, any advice is appreciated.

Thanks @Glenn Reyes, here's a Sandbox to show the problem.

import React from 'react';
import { render } from 'react-dom';

const SpecialButton = ({ children, color }) => (
  <button style={{color}}>{children}</button>
);

const htmlFromCMS = `
<div>Hi, 
  <SpecialButton color="red">My Button</SpecialButton>
</div>`;

const App = () => (
  <div dangerouslySetInnerHTML={{__html: htmlFromCMS}}>
  </div>
);

// expect to be same as
// const App = () => (
//   <div>Hi, 
//     <SpecialButton color="red">My Button</SpecialButton>
//   </div>
// );

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

Here is a live demo made by Vuejs. String "<div v-demo-widget></div>" could be treat as Vuejs directive and rendered. Source Code.

4

6 Answers

You probably want to look deeper into dangerouslySetInnerHTML. Here is an example how to render HTML from a string in a React component:

import React from 'react';
import { render } from 'react-dom';

const htmlString = '<h1>Hello World! 👋</h1>';

const App = () => (
  <div dangerouslySetInnerHTML={{ __html: htmlString }} />
);

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

Full example here:

Read more about dangerouslySetInnerHTML in the React docs here:

6

You can use the react-html-parser in case you don't want to use dangerouslySetInnerHTML attribute

import React from 'react';
import { render } from 'react-dom';
import ReactHtmlParser from 'react-html-parser';

const SpecialButton = ({ children, color }) => (
  <button style={{color}}>{children}</button>
);

const htmlFromCMS = `
<div>Hi, 
  <SpecialButton color="red">My Button</SpecialButton>
</div>`;

const App = () => (
  <div>
     {ReactHtmlParser(htmlFromCMS)}
  </div>
);


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

Happy Coding!!!

4

As pointed out in this answer by EsterlingAccimeYoutuber, you can use a parser in case you don't want to use dangerouslySetInnerHTML attribute.

By now, react-html-parser has not been updated for 3 years, so I went looking for a different module.

html-react-parser does same job but is frequently maintained and updated.

It should be good practice to sanitize your html-String to prevent XSS attacks. dompurify can be used for that.

I updated EsterlingAccimeYoutuber's code-example to the following:

import React from 'react';
import { render } from 'react-dom';
import parse from 'html-react-parser';
import DOMPurify from 'dompurify';

const SpecialButton = ({ children, color }) => (
  <button style={{color}}>{children}</button>
);

const htmlFromCMS = `
<div>Hi, 
  <SpecialButton color="red">My Button</SpecialButton>
</div>`;

const htmlFrom = (htmlString) => {
        const cleanHtmlString = DOMPurify.sanitize(htmlString,
          { USE_PROFILES: { html: true } });
        const html = parse(cleanHtmlString);
        return html;
}

const App = () => (
  <div>
     {htmlFromCMS && htmlFrom(htmlFromCMS)}
  </div>
);


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

Inspired by original post above, hence special thanks to original authors!

1

For any from the future just enhancement of GProst Answer, You can use ReactDOMserver, This is how we can implement the same.

import React from "react";
import { render } from "react-dom";
import { renderToString } from "react-dom/server";

const SpecialButton = ({ children, color }) => (
  <button style={{ color }}>{children}</button>
);

const renderButton = renderToString(<SpecialButton>MyButton</SpecialButton>);

const htmlFromCMS = `
<div>Hi, 
  ${renderButton}
</div>`;

const App = () => <div dangerouslySetInnerHTML={{ __html: htmlFromCMS }} />;

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

You can try use ReactDOMserver to render <MyReactComponent /> into html on your server and then pass it to the client, where you can insert all received html via dangerouslySetInnerHTML.

7

This is my way to use html-react-parser and react onClick event together.

import React from "react";
import { render } from "react-dom";
import parse from "html-react-parser";

const html = `
  <div style="font-size:32px;">html-react-parser with js events</div>
  <div>This is a long long long text.<div id="supportEmail"></div>t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.</div>
`;

const handlefunction = () => {
  alert("Clicked");
};

const replace = (domNode) => {
  if (domNode.attribs && domNode.attribs.id === "supportEmail") {
    return (
      <code>
        <div
          style={{
            backgroundColor: "gray",
            padding: "4px 8px",
            width: "100px",
            textAlign: "center"
          }}
          onClick={handlefunction}
        >
          Click
        </div>
      </code>
    );
  }
};

function App() {
  return parse(html, { replace });
}

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

Check example in Codesandbox

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Chloe Bennett

Chloe Bennett

Culture, Media & Entertainment Columnist

Chloe Bennett explores the intersection of pop culture, streaming entertainment, digital trends, and contemporary lifestyle. Her weekly commentary reaches thousands of culture enthusiasts.

Share this article
Twitter Facebook Pinterest