How to make iFrames auto-resize to 100% height based on content

Do you need to ensure your iframe’s height is always set to 100% of the height of the content you are embedding? If so, keep on reading.

This page contains freely-usable code for responsive iFrames. iFrame height will adjust based on the height of the content in them. The code works for cross-domain iFrames and does not use any libraries like jQuery.

The problem

As a Marketing Operations professional, I often need to put marketing forms onto webpages. Normally, I would put code like this onto the page so the form appears in an iFrame:

<iframe src="https://mydomain.com/the-form.html" style="width:1px; min-width:100%; border-width: 0px;" allowtransparency="true"></iframe>

The problem with iFrames is that you don’t always know their full height. Also, their height can change unexpectedly.

When that happens, an unattractive scrollbar gets added next to the content – and the content no longer looks like it is a natural part of the parent webpage.

Below is an example of a Pardot marketing form that’s been embedded using an iFrame. Note what happens when the form is submitted with missing information: several error messages appear and add a distracting scrollbar at the right side.

This GIF shows an iFrame bar appear after the embedded form’s content gets taller

What we want is for the form’s iFrame to grow vertically so that all the content shows up. No scrollbar.

Note: The animation of the Pardot form above is using a form from a post by Alex Avendano at EBQ, on customizing the design of Pardot forms. That post contains some great sample code for making your forms look good.

The solution

I have prepared some JavaScript code that solves the problem. It monitors the iFrame for changes in height, and then uses the Window​.post​Message() mechanism to instruct the parent page to resize the iFrame. This works even when the 2 pages are on completely different domains (which is usually a big challenge).

You are free to use this code for any purpose, under the MIT License.

Using the code on your site

Copy the following code onto the <body> of the parent hosting the iFrame:


<script>
/*
MIT License

Copyright (c) 2019 Jacob Filipp

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/



// Add this script to the parent page on which your iFrame is embedded
// This code resizes the iFrame's height in response to a postMessage from the child iFrame



// event.data - the object that the iframe sent us
// event.origin - the URL from which the message came
// event.source - a reference to the 'window' object that sent the message
function gotResizeMessage(event)
{
	console.log( "got resize message: " + JSON.stringify(event.data))
	
	var matches = document.querySelectorAll('iframe'); // iterate through all iFrames on page
	for (i=0; i<matches.length; i++)
	{
		if( matches[i].contentWindow == event.source ) // found the iFrame that sent us a message
		{
			console.log("found iframe that sent a message: " + matches[i].src)
				
			//matches[i].width = Number( event.data.width )	 <-- we do not do anything with the page width for now
			matches[i].height = Number( event.data.height )
			
			return 1;
		}
	}
}
	    
document.addEventListener("DOMContentLoaded", function(){
	
	window.addEventListener("message", gotResizeMessage, false)
	
}); //on DOM ready
</script>


Copy this second script into the <body> of the page that will be contained in the iFrame:


<script>
/*

MIT License

Copyright (c) 2019 Jacob Filipp

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/


// Add this script into the page that will appear inside an iFrame
// This code monitors the page for changes in size. When change is detected, it sends send the latest size to the parent page using postMessage


// determine height of content on this page
function getMyHeight()
{
	//https://stackoverflow.com/a/11864824
	return Math.max( document.body.scrollHeight, document.documentElement.scrollHeight)
}


// send the latest page dimensions to the parent page on which this iframe is embedded
function sendDimensionsToParent()
{
	var iframeDimensions_New = {
				'width': window.innerWidth, //supported from IE9 onwards
				'height': getMyHeight()
			};
			
	if( (iframeDimensions_New.width != iframeDimensions_Old.width) || (iframeDimensions_New.height != iframeDimensions_Old.height) )  // if old width is not equal new width, or old height is not equal new height, then...
	{
		
		window.parent.postMessage(iframeDimensions_New, "*");
		iframeDimensions_Old = iframeDimensions_New;
		
	}
		
}


// on load - send the page dimensions. (we do this on load because then all images have loaded...)
window.addEventListener( 'load', function(){
	
		
	iframeDimensions_Old = {
						'width': window.innerWidth, //supported from IE9 onwards
						'height': getMyHeight()
					};

	window.parent.postMessage(iframeDimensions_Old, "*"); //send our dimensions once, initially - so the iFrame is initialized to the correct size


	if( window.MutationObserver ) // if mutationobserver is supported by this browser
	{
		//https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

		var observer = new MutationObserver(sendDimensionsToParent);
		config = {
			  attributes: true,
			  attributeOldValue: false,
			  characterData: true,
			  characterDataOldValue: false,
			  childList: true,
			  subtree: true
		};

		observer.observe(document.body, config);
		
	}
	else // if mutationobserver is NOT supported
	{
		//check for changes on a timed interval, every 1/3 of a second
		window.setInterval(sendDimensionsToParent, 300);
	}


});   // end of window.onload

</script>

Alternatively, you can save this file to your server and reference is using <script src="yourpath/parentcode.js"></script> from the page hosting the iFrame.

You would then download this file to your server and add it to the page contained in the iFrame using <script src="yourpath/iframecode.js"></script> .

Improvements + feedback

You can improve this code for everyone if you send me your feedback. If you run into a bug, or successfully modify the code to solve a bug, then please share this information with me. Either comment on this post or email me at “j@thisdomain” .

Implementing the code for Pardot forms

The iFrame-resizing issue is a special pain for Pardot marketing forms – when you are looking to embed a form onto a page on your main website (which means that you have a cross-domain iFrame).

Here are some concrete steps for implementing the code above in Pardot:

  1. Click on the “Marketing” navigation item
  2. “Forms”
  3. “Layout Templates”

This will let you alter the code that appears with every Pardot form that will be contained inside an iFrame

Go to the template you use most often to render your forms. In our system, we use the default template called “Standard”. Click on it.

Next, click “Edit” on the layout template.
When you are editing, open the Form tab to edit code that only has to do with forms (other layout code tabs are for other things, like landing pages). Finally, copy the Javascript code for the page that will be contained inside an iFrame and paste it where the arrow below indicates (right before the <form> opening tag).

Finally, add the “parent hosting the iFrame” code onto the page on your site where you’ll embed the Pardot form. You can do this by linking the “parentcode.js” file to the page.

Together, these 2 pieces of code are going to ensure that your marketing forms look like they belong on your page – without any scrollbars.

A more advanced solution

When researching this post, I came across a much more robust package for dynamic iFrame resizing called “iFrame Resizer” (and accessible at https://github.com/davidjbradshaw/iframe-resizer) . The creator is David Bradshaw. David’s package detects many more “resize” events than my code – events such as a mobile device being rotated, or a CSS animation affecting the size of the iFrame.

If you need a more heavy-duty solution to the iFrame dynamic height problem then give the “iFrame Resizer” a try.


This entry was posted in Writing. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *