Iframe – change window size (cross domain) - createIT
Get a free advice now!

    Pick the topic
    Developer OutsourcingWeb developingApp developingDigital MarketingeCommerce systemseEntertainment systems

    Thank you for your message. It has been sent.

    Iframe – change window size (cross domain)

    October 11, 2022
    Last update: February 8, 2023
    3 min read
    48
    0
    0
    Iframe – change window size (cross domain)

    CHALLENGE: change iframe size from the inside

    SOLUTION: use browser window.postMessage() Web API

    We would like to embed our React App inside iframe on a third-party domain. How to add the ability to dynamically change window size from inside the iframe? Let’s find out.

    Websites are protected by CORS policy, which forbids iframes from making changes in the parent site DOM. This security policy blocks malicious actions from third-party embeds.

    postMessage

    By default, scripts can modify DOM of the page only if they share the same host and protocol (same origin policy). The window.postMessage() method enables cross-origin communication between a page and an iframe embedded within it. It allows to dispatch MessageEvent from one window and to receive it in another.

    Iframe – changing window size

    We need to take 2 steps to have the ability to change iframe size (width and height) and trigger it from iframe code:

    • add iframe code to the parent page and window.addEventListener
    • use postMessage inside iframe to trigger size changes

    Iframe embed

    We’re going to paste our iframe embed code on the parent website. There is parent div “iframe-parent” that controls the width and height, and iframe displays our React App content. The last part is window.addEventListener that is waiting to receive messages from iframe. When a message is received, inline styles are applied to the div.

    <!-- public/parent.html  -->
    <html>
    <head></head>
    <body style="background:#ccc; border:4px solid #999; padding:10px; margin:0;">
    <h1>This is parent page</h1>
    <div id="iframe-parent"
         style="border: 0px;
         background-color: #282c34;
         pointer-events: none;
         z-index: 2147483639;
         position: fixed;
         bottom: 0px;
         width: 300px;
         height: 400px;
         overflow: hidden;
         opacity: 1;
         max-width: 100%;
         right: 0px;
         max-height: 100%;">
        <iframe src="http://localhost:3001" id="iframe-source"
                style="pointer-events: all;
                background: none;
                border: 0px;
                float: none;
                position: absolute;
                inset: 0px;
                width: 100%;
                height: 100%;
                margin: 0px;
                padding: 0px;
                min-height: 0px;">
        </iframe>
    </div>
    <script>
        // communication
        const iframeParent = document.getElementById("iframe-parent");
        window.addEventListener('message', function (e) {
            let message = e.data;
            if (!iframeParent) {
                return;
            }
            iframeParent.style.height = message.height;
            iframeParent.style.width = message.width;
            iframeParent.style.background = message.background;
        }, false);
    </script>
    </body>
    </html>

    Change iframe parent size

    Iframe uses React to showcase an example of using window.parent.postMessage. But it’s just javascript, it can be used without React. It is enough to use plain javascript to establish a connection with iframe. On button click, we’re sending a message to the parent page to adjust the styles of div with ID #iframe-parent. Active class is just for better presentation (highlighting the recently clicked button).

    // src/App.jsx
    import React, {useState} from 'react';
    import './App.css';
    function App() {
      const [active, setActive] = useState('button0');
      const changeIframeParentSize = (width = '300px', height = '300px', background = '#282c34') =>{
        let message = { height: height, width: width, background: background };
        window.parent.postMessage(message, "*");
      }
      return (
        <div className="App">
          <header className="App-header">
            <div className={'App-body'}>
              <h2>Change window size from iframe</h2>
              <button id={'button0'}
                      key={'button0'}
                      className={active === 'button0' ? "active" : undefined}
                      onClick={(event)=> { setActive(event.target.id); changeIframeParentSize('300px','400px')}}>300px x 400px</button>
              <button id={'button1'}
                      key={'button1'}
                      className={active === 'button1' ? "active" : undefined}
                      onClick={(event)=> { setActive(event.target.id); changeIframeParentSize('800px','800px')}}>800px x 800px</button>
              <button id={'button2'}
                      key={'button2'}
                      className={active === 'button2' ? "active" : undefined}
                      onClick={(event)=> { setActive(event.target.id); changeIframeParentSize('400px','400px', 'pink')}}>400px x 400px and pink</button>
              <button id={'button3'}
                      key={'button3'}
                      className={active === 'button3' ? "active" : undefined}
                      onClick={(event)=> { setActive(event.target.id); changeIframeParentSize('600px','600px')}}>600px x 600px</button>
              <button id={'button4'}
                      key={'button4'}
                      className={active === 'button4' ? "active" : undefined}
                      onClick={(event)=> { setActive(event.target.id); changeIframeParentSize('300px','500px', 'red')}}>300px x 500px and red</button>
            </div>
          </header>
        </div>
      );
    }
    export default App;

    and styles needed for the Demo example:

    .App {
      text-align: center;
      background-color: transparent;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      font-size: calc(10px + 2vmin);
      color:#fff;
      padding:20px;
    }
    .App-body button {
      cursor:pointer;
      margin:10px;
      border:0;
      padding:5px 10px;
      background:#fff;
      color:#282c34;
    }
    .App-body button.active {
      background:darkslategrey;
      color:#fff;
    }

    Changing styles from iframe

    Changing width and height of div is only one option. You can also change any other styles from iframe. It’s just a matter of passing an additional parameter to the changeIframeParentSize function and adding an extra line in parent.html :

    <script>
    // communication
    ..
    iframeParent.style.background = message.background;
    </script>

    Cross domain

    In our example, we’re using the same domain: http://localhost:3001/parent.html and http://localhost:3001 for iframe source. So, technically, we don’t have proof that this will work cross-origin (having a parent website and iframe using different domains).

    If we have the React application, we can upload our code to Netlify really fast and test it cross domain. For Netlify deployment, we need to execute the following in the console:

    // One time:
    npm install netlify-cli -g
    // To deploy the code:
    npm run build
    netlify deploy
    build (Publish directory)
    netlify deploy --prod

    Now, we can visit the /parent.html site hosted on Netlify, and iframe will be still pointing to the localhost url. I have good news, it is still working! PostMessage API provides an easy way to enable communication with iframe having the parent website hosted on a different domain.

    Animation of a browser window and switching between website window sizes

    That’s it for today’s tutorial. Make sure to follow us for other useful guidelines and don’t forget to sign up for our newsletter.

    Support – Tips and Tricks
    All tips in one place, and the database keeps growing. Stay up to date and optimize your work!

    Contact us