2

I would like to know how to load the HTML form in the iframe in reactjs.

I have one form component that has all the input fields, and I want to load that form component in the iframe. I would like to know how I can do that.

const Form = () => {
  return (
    <>
      <iframe name="iframe-form" title="This is an iframe form." />
    <form target="iframe-form" onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">Name</label>
        <input
          type="text"
          id="name"
        />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <input type="email" id="email" />
      </div>
      <button>Submit</button>
    </form>
</>
  );
};

export default Form;

Currently, it's rendering like this. enter image description here

r121
  • 2,478
  • 8
  • 25
  • 44
  • Is it possible to host this form somewhere and use an absolute path of it in an iframe? – Neha Soni Nov 25 '22 at 11:02
  • No, it's a part of the project, so I can't host it. – r121 Nov 25 '22 at 14:39
  • Does this answer your question? [How to set iframe content of a react component](https://stackoverflow.com/questions/34743264/how-to-set-iframe-content-of-a-react-component) – ksav Nov 26 '22 at 05:58

2 Answers2

1

According to the React documentation, 'React Portals' allow us to render children into a DOM node that exists outside of the parent component’s DOM hierarchy. Basically, portals let us render children wherever we want to.

So the large explanation would be create a portal:

ReactDOM.createPortal(child, container)

In this case, the child is a React element, fragment, or string, and the container is the DOM location or node to which the portal should be rendered.

With a React portal, we can choose where to place a DOM node in the DOM hierarchy, the portal’s contents are also considered children of the parent’s virtual DOM.

MyComponent.js

import React from 'react'

function MyComponent() {
    return (
        <div>
            <p style={{color: 'red'}}>Testing to see if my component renders!</p>
        </div>
    )
}

export default MyComponent;

Now, let’s create a file called CustomIframe.js and write the following code:

import React, { useState } from 'react'
import { createPortal } from 'react-dom'

const CustomIframe = ({
  children,
  ...props
}) => {
  const [contentRef, setContentRef] = useState(null)

  const mountNode =
    contentRef?.contentWindow?.document?.body

  return (
    <iframe {...props} ref={setContentRef}>
      {mountNode && createPortal(children, mountNode)}
    </iframe>
  )
}

export default CustomIframe;

We created a ref with the useState() Hook, therefore, once the state is updated, the component will re-render.

We also got access to the iframe document body, then created a portal to render the children passed to iframe in this body instead:

import './App.css';
import CustomIframe from './CustomIframe';
import MyComponent from './MyComponent';
function App() {


  return (
    <CustomIframe title='A custom made iframe'>
        <MyComponent />
      </CustomIframe>
  );
}

export default App;

You can pass any React app or component as a child of CustomIframe, and it should work fine.

The React app or component will become encapsulated, meaning you can develop and maintain it independently.

You can also achieve the same encapsulation as above using a library called react frame component. To install it, run the following command:

npm install --save react-frame-component

Encapsulate your component as follows:

import Frame from 'react-frame-component';

function App() {

  return (
    <div className='App'>
        <p>Iframes in React</p>
        <Frame >
           <MyComponent />
        </Frame>
    </div>
  );
}

export default App;
Gonzalo Cugiani
  • 459
  • 2
  • 15
  • This worked, but now my Form component styling doesn’t get applied. Any idea how to fix that? I tried to import the `App.css` file in the Form component directly, but it still didn’t work. – r121 Nov 26 '22 at 06:02
  • That is because we could use the `srcdoc` attribute, which takes in an inline HTML to embed, however we’re then trying to render an entire app or component, with uses extensive and verbose code, so I would recommend find a way to render the component in the iframe body instead of as a child of it, and for that, we should use a portal. I find this similar [related post](https://stackoverflow.com/questions/57405409/injecting-css-to-a-window-document-when-using-react-portal) could fix your issue about styles. – Gonzalo Cugiani Nov 26 '22 at 06:17
  • The attached post doesn't have any answers. – r121 Nov 26 '22 at 06:20
  • I wanted to attach [this post](https://stackoverflow.com/questions/65991135/how-to-include-styles-in-react-create-portal) sorry, I can't edit the comment above anymore. – Gonzalo Cugiani Nov 26 '22 at 06:45
1

Use ReactDOMServer.renderToString with iframe's srcDoc attribute.

import ReactDOMServer from "react-dom/server";

export default function App() {
  return (
    <div className="App">
      <iframe
        name="iframe-form"
        title="This is an iframe form."
        srcDoc={ReactDOMServer.renderToString(<Form />)}
      />
    </div>
  );
}

const Form = () => {
  return (
    <form target="iframe-form">
      <div>
        <label htmlFor="name">Name</label>
        <input type="text" id="name" />
      </div>
      <div>
        <label htmlFor="email">Email</label>
        <input type="email" id="email" />
      </div>
      <button>Submit</button>
    </form>
  );
};

Edit react iframe with inline content

ksav
  • 20,015
  • 6
  • 46
  • 66