Inject JSX-formatted string into React Component
I originally provided an answer as to how you can insert a string as HTML directly into React. However, since you also want variables inside your string to be parsed (and other potential logic) before it being inserted into React, I have left both options here as they might be useful for future readers.
Case 1 - Your string is ready to be inserted
If the string containing your HTML is ready to be directly inserted into React, and does not contain code that needs to be parsed first, you should use dangerouslySetInnerHTML
. You should set it on the wrapping div that will contain the HTML fetched from your API.
See the example below.
var htmlFromApi = '<div className="button-basics-example"><Button color={Colors.SUCCESS}>Save</Button><Button color={Colors.ALERT}>Delete</Button></div>';
var App = ({html}) => { return <div dangerouslySetInnerHTML={{ __html: html}}></div> }
ReactDOM.render(<App html={htmlFromApi}/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="app"></div>
Case 2 - Your string is not ready and needs additional logic before being inserted
If your string isn't "ready" to be injected directly into the DOM, but needs some kind of processing first (e.g your string contains variables that need to be interpreted first), things get more complicated. Unfortunately, there is no good nor "recommended" way to do this.
- If the manipulation required is simple and fairly static, you could perhaps use regex. Though this approach comes with limitations. Use cases for this approach might be manipulating a DOM class or adding an element to the string.
- Another approach is to use a library, such as html-to-react, that might help you with what you are looking for.
- Finally, if you are using Babel (which you almost certainly are), you could use the Babel transformer. All you need is to import
babel-core
into your code and transform the string into JSX. This approach might be more limited than using a library, but it should suffice.
Here's how to implement point #3 from above:
Babel.transform(code, options);
Where code
is your html-string. In options
we need to pass an object with {presets: ['react']}
so that Babel understands that want JSX as our output. You could of course add other options here also.
This will return an object that contains stuff like the source-map, but we are only interested in the generated code here. So we need to add:
Babel.transform(code, options).code;
Note that code
is javascript code in a string-format and it expresses a function call to create a React Element with React.createElement
. To execute a string as code in javascript, we can use eval()
.
We can then add this React Element into our React Component and render it normally, as shown in the example below.
var htmlFromApi = '<div className="button-basics-example"><Button color={Colors.SUCCESS}>Save</Button><Button color={Colors.ALERT}>Delete</Button></div>';
var Colors = {SUCCESS: "green", ALERT: "red"};
var App = ({html}) => {
var Component = Babel.transform(htmlFromApi, {presets: ["react"]}).code;
return <div>{eval(Component)}</div>;
};
var Button = ({color, children}) => (
<button style={{backgroundColor: color}}>{children}</button>
);
ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
For more details about Babel.transform
, see the official documentation.
Related videos on Youtube
Comments
-
Rana almost 2 years
I have a small react page that should compile and display html string. the html in the string written in react-foundation
The page looks like this :
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Link, Button, Colors } from 'react-foundation'; require('./foundation.css') var htmlFromApi = '<div className="button-basics-example"><Button color={Colors.SUCCESS}>Save</Button><Button color={Colors.ALERT}>Delete</Button></div>'; var App = ({ html }) => { return <div>{html}</div> } ReactDOM.render( <App html={htmlFromApi}/>, document.getElementById('react') );
The Result of the above code is just a string, I am wondering if there is a way to convert the html string to react element
something like this :
var reactElement= toReactElement(htmlFromApi); //the result is <div className="button-basics-example"><Button color={Colors.SUCCESS}>Save</Button><Button color={Colors.ALERT}>Delete</Button></div>
PS I tried
<div className="content" dangerouslySetInnerHTML={{ __html: htmlFromApi }}></div>
and didn't workThanks in advance
Edit: the code is here
-
Dan over 6 yearsTry using dangerouslySetInnerHTML - facebook.github.io/react/docs/…
-
Isa Ishangulyyev over 6 yearsHow about React.createElement(elementString, propsObject) ?
-
Rana over 6 years@Dan didn't work, bcz dangerouslySetInnerHTML expect compiled html string, but the string I have is not compiled
-
Rana over 6 years@isa424 I cannot use React.createElement bcz I don't know how the string will look like, and it is very long string with so many nested components
-
-
Rana over 6 yearsthanks for your answer, but this way the values inside the string will not be evaluated or compiled , am I right , sorry I am very poor with react
-
Rana over 6 yearsthis is how the result looks like with css in place codepen.io/anon/pen/oeddYN?editors=1111
-
Dan Zuzevich over 6 yearsJust a quick note, but I don't think you want to include className in the outer div, as it doesn't output properly. It ends up with an attribute of classname="button-basics-example" inside the browser. Using just the word class, and then setting some styling for button-basic-example in the css inside of your pen, I was able to produce some styling, but not when it uses className inside of the html string. Any thoughts on that?
-
Rana over 6 years@DanielZuzevich dangerouslySetInnerHTML expect compiled html, so there is no way to make it compile string that has components inside like<Button />, and the string that I have is non compiled html , so I need a way to compile the html then pass it to dangerouslySetInnerHTML
-
Chris over 6 years@Rana, I have updated my answer. Please have a look.
-
Rana over 6 years@Chris : I just reached the point u mentioned in the comment, but could not make Babel work in my page ? it this the way we import it ( import * as babel from 'babel-core' ) , note that I have this version ("babel-core": "^6.26.0",) and i am using "webpack": "^3.5.0",
-
Rana over 6 years@Chris: i faced this problem with babel github.com/babel/babel/issues/2961
-
Rana over 6 years@Chris: why u defined a Button and Colors comonents? if u remove them and add import { Link, Button, Colors } from 'react-foundation'; then the above dove will not work, the string will contain much more than Buttons , it will use almost all components in react-foundation, do u have any idea how can we make it work with react-foundation?
-
Rana over 6 years@Chris, the error is : after using description file: C:\Test\X\Scripts\Z\node_modules\babel-core\package.json (relative path: ./lib/helpers) resolve as module C:\Test\X\Scripts\Z\node_modules\babel-core\lib\helpers\node_modules doesn't exist or is not a directory C:\Test\X\Scripts\Z\node_modules\babel-core\lib\node_modules doesn't exist or is not a directory C:\Test\X\Scripts\Z\node_modules\babel-core\node_modules doesn't exist or is not a directory C:\Test\X\Scripts\Z\node_modules\node_modules doesn't exist or is not a directory
-
Rana over 6 years@Chris : babel-core didn't work for me, but babel-standalone worked fine but i had to define the components i use in the htmlString in the same file, did't accept 'import {Button} from 'react-foundation' '
-
Rodrigo Pires almost 6 yearsHey @Chris, I'm trying to implement your solution but I'm having problem importing
babel-core
into my React component. Wepack says it can't resolve babel-core module. Any tips on that? Thank you! -
Chris almost 6 years@RodrigoPires, well, first off I highly suggest going with the 1st option I provided, if possible. If you still want to go with option (2): Did you do
npm install babel-core
? (or yarn if you use that) -
Rodrigo Pires almost 6 years@Chris In my case, I need a full jsx expression to be stored in a string and then evaluated to jsx, including objects/variables and conditionals. ie:
<span className={item.active ? "active" : ""}>{item.name}<span>
. So yes, I've installed and importedbabel-core
, that's when the error occurs. If you also know any other solution for my scenario, please let me know! Tks!