Reputation: 4052
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.
Upvotes: 51
Views: 142933
Reputation: 7
Simple and easiest way to achieve parser by using dangerouslySetInnerHTML attribute.
const htmlString = '<h1>Hello World! 👋</h1>';
const App = () => (
<div dangerouslySetInnerHTML={{ __html: htmlString }} />
);
Upvotes: 0
Reputation: 1
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
Upvotes: 0
Reputation: 1564
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!
Upvotes: 28
Reputation: 4718
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!!!
Upvotes: 24
Reputation: 683
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"));
Upvotes: 1
Reputation: 2349
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: https://codesandbox.io/s/xv40xXQzE
Read more about dangerouslySetInnerHTML
in the React docs here: https://facebook.github.io/react/docs/dom-elements.html#dangerouslysetinnerhtml
Upvotes: 57
Reputation: 10237
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
.
Upvotes: 0