81

Is it possible to render HTML from another file in a React component?

I have tried the following, but it does not work:

var React = require('react');

/* Template html */
var template = require('./template');

module.exports = React.createClass({
    render: function() {
        return(
            <template/>
        );
    }
});
stef
  • 14,172
  • 2
  • 48
  • 70
Emir Marques
  • 2,603
  • 2
  • 16
  • 22
  • 2
    You have to use capital letter for custom components, so rename `template` to `Template` and then return it as `` – Icepickle Nov 28 '15 at 16:45
  • 1
    I assume that when you say "HTML", you really mean JSX? – Felix Kling Nov 28 '15 at 16:46
  • @Icepickle i get this error: Uncaught Error: Cannot find module "./template" – Emir Marques Nov 28 '15 at 16:49
  • Logic, i get this per file not is jsx and not contains "module.exports = any". I can import html file with other form? – Emir Marques Nov 28 '15 at 16:51
  • 1
    Well, the module has to exist to be able to import it. I'm not sure what your second comment is supposed to mean. Please [edit] your question and add all the relevant information. With 1k rep, you should know how to properly write a question. If not, here is a reminder: [ask] – Felix Kling Nov 28 '15 at 16:52
  • Using an iframe jsx component would allow you to add the contents of a whole page into a react application. I haven't tried this, but react-iframe (https://www.npmjs.com/package/react-iframe) looks quite popular. The subject is also discussed on Stack Overflow here: https://stackoverflow.com/questions/33913737/inserting-the-iframe-into-react-component – Francis Jul 23 '18 at 06:38

6 Answers6

67

If your template.html file is just HTML and not a React component, then you can't require it in the same way you would do with a JS file.

However, if you are using Browserify — there is a transform called stringify which will allow you to require non-js files as strings. Once you have added the transform, you will be able to require HTML files and they will export as though they were just strings.

Once you have required the HTML file, you'll have to inject the HTML string into your component, using the dangerouslySetInnerHTML prop.

var __html = require('./template.html');
var template = { __html: __html };

React.module.exports = React.createClass({
  render: function() {
    return(
      <div dangerouslySetInnerHTML={template} />
    );
  }
});

This goes against a lot of what React is about though. It would be more natural to create your templates as React components with JSX, rather than as regular HTML files.

The JSX syntax makes it trivially easy to express structured data, like HTML, especially when you use stateless function components.

If your template.html file looked something like this

<div class='foo'>
  <h1>Hello</h1>
  <p>Some paragraph text</p>
  <button>Click</button>
</div>

Then you could convert it instead to a JSX file that looked like this.

module.exports = function(props) {
  return (
    <div className='foo'>
      <h1>Hello</h1>
      <p>Some paragraph text</p>
      <button>Click</button>
    </div>
  );
};

Then you can require and use it without needing stringify.

var Template = require('./template');

module.exports = React.createClass({
  render: function() {
    var bar = 'baz';
    return(
      <Template foo={bar}/>
    );
  }
});

It maintains all of the structure of the original file, but leverages the flexibility of React's props model and allows for compile time syntax checking, unlike a regular HTML file.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
Dan Prince
  • 29,491
  • 13
  • 89
  • 120
  • Its works, but not working with material-ui. My html file contains TextField and not render – Emir Marques Nov 29 '15 at 14:04
  • Sorry, I'm not following. Which approach did you try? Is there an error? Maybe it would be helpful to include your html file in your question. – Dan Prince Nov 29 '15 at 14:05
  • 1
    I'm getting an error: Uncaught (in promise) Error: Module parse failed: C:\Users\....\target.html Unexpected token (1:0) You may need an appropriate loader to handle this file type. | | ; | – Zack Zilic Jun 11 '18 at 08:45
  • do you need to do any ->npm install xxxx<- or to change anything in web.confing?? – Zack Zilic Jun 11 '18 at 08:46
  • 3
    @ZackZilic You need to install [html-loader](https://github.com/webpack-contrib/html-loader) and then configure it in your Webpack config file. – Dan Prince Jun 11 '18 at 13:43
  • Please provide more detail, I've tried by your answer and still got errors. – Thien Nhan Nguyen Sep 25 '18 at 06:01
8

You can use the dangerouslySetInnerHTML property to inject arbitrary HTML:

// Assume from another require()'ed module:
var html = '<h1>Hello, world!</h1>'

var MyComponent = React.createClass({
  render: function() {
    return React.createElement("h1", {dangerouslySetInnerHTML: {__html: html}})
  }
})

ReactDOM.render(React.createElement(MyComponent), document.getElementById('app'))
<script src="https://fb.me/react-0.14.3.min.js"></script>
<script src="https://fb.me/react-dom-0.14.3.min.js"></script>
<div id="app"></div>

You could even componentize this template behavior (untested):

class TemplateComponent extends React.Component {
  constructor(props) {
    super(props)
    this.html = require(props.template)
  }

  render() {
    return <div dangerouslySetInnerHTML={{__html: this.html}}/>
  }

}

TemplateComponent.propTypes = {
  template: React.PropTypes.string.isRequired
}

// use like
<TemplateComponent template='./template.html'/>

And with this, template.html (in the same directory) looks something like (again, untested):

// ./template.html
module.exports = '<h1>Hello, world!</h1>'
Jon Surrell
  • 9,444
  • 8
  • 48
  • 54
7

You can use dangerouslySetInnerHTML to do this:

import React from 'react';
function iframe() {
    return {
        __html: '<iframe src="./Folder/File.html" width="540" height="450"></iframe>'
    }
}


export default function Exercises() {
    return (
        <div>
            <div dangerouslySetInnerHTML={iframe()} />
        </div>)
}

HTML files must be in the public folder

1

It is common to have components that are only rendering from props. Like this:

class Template extends React.Component{
  render (){
    return <div>this.props.something</div>
  }
}

Then in your upper level component where you have the logic you just import the Template component and pass the needed props. All your logic stays in the higher level component, and the Template only renders. This is a possible way to achieve 'templates' like in Angular.

There is no way to have .jsx file with jsx only and use it in React because jsx is not really html but markup for a virtual DOM, which React manages.

Ivan
  • 16,536
  • 6
  • 23
  • 36
  • Tanks for your response. But when use big html page, this method will have various lines in one file jsx. I not can create one file jsx for each demand. – Emir Marques Nov 28 '15 at 16:55
  • There is no need to have a jsx file for every line/block. When working with React you split the app into logical components based on what data every component uses, and using this logic you arrange your components. For example you can have a component that fetches users data from server. Let's say it's named UsersData. Then you have a component for the user, named UserData. And finally component rendering some piece of data, for example Biography. So the order is: UsersData -> UserData -> Biography. The biography component can have fields like birthplace and age. – Ivan Nov 28 '15 at 17:01
1

You could do it if template is a react component.

Template.js

var React = require('react');

var Template = React.createClass({
    render: function(){
        return (<div>Mi HTML</div>);
    }
});

module.exports = Template;

MainComponent.js

var React = require('react');
var ReactDOM = require('react-dom');
var injectTapEventPlugin = require("react-tap-event-plugin");
var Template = require('./Template');

//Needed for React Developer Tools
window.React = React;

//Needed for onTouchTap
//Can go away when react 1.0 release
//Check this repo:
//https://github.com/zilverline/react-tap-event-plugin
injectTapEventPlugin();

var MainComponent = React.createClass({
    render: function() {
        return(
            <Template/>
        );
    }
});

// Render the main app react component into the app div.
// For more details see: https://facebook.github.io/react/docs/top-level-api.html#react.render
ReactDOM.render(
  <MainComponent />,
  document.getElementById('app')
 );

And if you are using Material-UI, for compatibility use Material-UI Components, no normal inputs.

Allan
  • 273
  • 1
  • 8
  • A note for future readers: `React.createClass` is deprecated from `React version 16.0`. https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass – Tom Walsh Mar 09 '23 at 14:20
0

i-frame src accepts only http protocols. So, if you are loading any static html from your machine, the browser URL will likely be "file: //home/myComputer/localOfFiles/myHTMLfile.html" and the correct path should be "http://localhost:3000/myHTMLfile.html".

You don't need to use any extension or anything else, you just move a myHTMLfile.html to your public folder in React code and try this path "http://localhost:3000/myHTMLfile.html". This solution is borrowed from here (worked for me though its for pdf rendering)-

https://github.com/wojtekmaj/react-pdf/issues/300#issuecomment-846226460