Embedding an external web app with an iframe is easy until the content inside starts changing height.
A fixed height usually creates one of two problems: too much empty space or an unwanted scrollbar.
For cross-origin iframes, the parent page cannot simply read the height of the embedded document because of the browser's same-origin policy.
A clean solution is to combine ResizeObserver with postMessage.
Inside the embedded page
The embedded application measures its own height and sends it to the parent:
function sendHeight() {
window.parent.postMessage(
{
type: "iframe-resize",
height: document.documentElement.scrollHeight
},
"https://example.com"
);
}
const observer = new ResizeObserver(sendHeight);
observer.observe(document.documentElement);
window.addEventListener("load", sendHeight);
ResizeObserver is useful because the height can change after the initial page load.
For example:
- images may load later
- accordions may open
- responsive layouts may change
- dynamic content may be added
- fonts may affect the layout
Instead of guessing a height, the iframe reports its actual size whenever something changes.
On the parent page
The parent listens for the message and updates the iframe:
const iframe = document.querySelector("#embedded-app");
window.addEventListener("message", (event) => {
if (event.origin !== "https://embedded.example.com") {
return;
}
if (event.data?.type !== "iframe-resize") {
return;
}
const height = Number(event.data.height);
if (!Number.isFinite(height) || height <= 0) {
return;
}
iframe.style.height = `${height}px`;
});
The iframe itself can stay simple:
<iframe
id="embedded-app"
src="https://embedded.example.com"
style="width: 100%; border: 0;"
></iframe>
Now the embedded content can grow or shrink without introducing an internal scrollbar.
Validate the origin
A common shortcut is:
window.parent.postMessage(data, "*");
That works, but it is better to specify the expected origin whenever possible.
The receiving page should also validate event.origin.
Treat messages coming from an iframe like any other external input: verify where they came from before using the data.
The result
This pattern keeps responsibilities clean:
- the embedded app knows its own content height
- the parent controls the iframe element
-
postMessageconnects both sides safely -
ResizeObserverreacts to layout changes
It is a simple approach, but it solves one of the most common problems with responsive cross-origin embeds without relying on arbitrary fixed heights.
This article was created with AI assistance and reviewed for technical accuracy before publication.
Top comments (0)