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