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>html-react-parser with js events</div> <div>This is a long long long text.<div></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

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

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

You Might Also Like