Skip to content

Instantly share code, notes, and snippets.

@pbojinov
Last active December 8, 2023 21:09
Show Gist options
  • Save pbojinov/8965299 to your computer and use it in GitHub Desktop.
Save pbojinov/8965299 to your computer and use it in GitHub Desktop.
Two way iframe communication- Check out working example here: http://pbojinov.github.io/iframe-communication/

Two way iframe communication

The main difference between the two pages is the method of sending messages. Recieving messages is the same in both.

Parent

Send messages to iframe using iframeEl.contentWindow.postMessage Recieve messages using window.addEventListener('message')

iframe

Send messages to parent window using window.parent.postMessage Recieve messages using window.addEventListener('message')

Live Example

http://pbojinov.github.io/iframe-communication/

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>iframe Window</title>
<style>
body {
background-color: #D53C2F;
color: white;
}
</style>
</head>
<body>
<h1>Hello there, i'm an iframe</h1>
<p>Send Message: <button id="message_button">Hi parent</button></p>
<p>Got Message:</p>
<div id="results"></div>
<script>
// addEventListener support for IE8
function bindEvent(element, eventName, eventHandler) {
if (element.addEventListener) {
element.addEventListener(eventName, eventHandler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, eventHandler);
}
}
// Send a message to the parent
var sendMessage = function (msg) {
// Make sure you are sending a string, and to stringify JSON
window.parent.postMessage(msg, '*');
};
var results = document.getElementById('results'),
messageButton = document.getElementById('message_button');
// Listen to messages from parent window
bindEvent(window, 'message', function (e) {
results.innerHTML = e.data;
});
// Send random message data on every button click
bindEvent(messageButton, 'click', function (e) {
var random = Math.random();
sendMessage('' + random);
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Parent Window</title>
</head>
<body>
<h1>Parent Window</h1>
<p>Send Message: <button id="message_button">Hi there iframe</button></p>
<p>Got Message:</p>
<div id="results"></div>
<br/>
<script>
// addEventListener support for IE8
function bindEvent(element, eventName, eventHandler) {
if (element.addEventListener){
element.addEventListener(eventName, eventHandler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, eventHandler);
}
}
var iframeSource = 'https://gist.github.com/pbojinov/8965299/raw/fadf2c4058b6481646e7244994c1890f2ad81b60/iframe.html';
// Create the iframe
var iframe = document.createElement('iframe');
iframe.setAttribute('src', iframeSource);
iframe.setAttribute('id', 'the_iframe');
iframe.style.width = 450 + 'px';
iframe.style.height = 200 + 'px';
document.body.appendChild(iframe);
// Send a message to the child iframe
var iframeEl = document.getElementById('the_iframe'),
messageButton = document.getElementById('message_button'),
results = document.getElementById('results');
// Send a message to the child iframe
var sendMessage = function(msg) {
// Make sure you are sending a string, and to stringify JSON
iframeEl.contentWindow.postMessage(msg, '*');
};
// Send random messge data on every button click
bindEvent(messageButton, 'click', function (e) {
var random = Math.random();
sendMessage('' + random);
});
// Listen to message from child window
bindEvent(window, 'message', function (e) {
results.innerHTML = e.data;
});
</script>
</body>
</html>
@justenh
Copy link

justenh commented Dec 5, 2019

Gonna leave a quick note of appreciate here as well. Thanks!

@Christopher-Hayes
Copy link

Helped me figure out why my code wasn't working, thanks!

@ChandanaRDeshmukh96
Copy link

I am trying this in angular. I am unable to get the iframe elem. Can anyone help?

@Christopher-Hayes
Copy link

Christopher-Hayes commented Mar 6, 2020

@ChandranaRDeshmukh96 Angular separates components in a way that makes it a difficult for them to access each other. Something like document.querySelector('#iframe-id') should still work though. Otherwise, you may have to make a service to give yourself access to that iframe element.

@leotengfei
Copy link

Thank you,very useful!

@justlester
Copy link

Thank you this helps me a lot! Just asking if is it possible to emit an event in all frames in a nested iframe?

@mrvisser
Copy link

@justlester you'll probably need to have the iframe at nesting level 1, propagate it to iframe at nesting level 2, and so on.

FWIW, I've created a library protoframe that adds a type wrapper around your iframe messaging protocol and has some helper functions to bind the listeners to the right window and establish "connection": https://github.com/mrvisser/protoframe

@greybax
Copy link

greybax commented Sep 8, 2020

great example! it helps me a lot while I've worked on VSC extension. I've described my process in my blog post here https://alfilatov.com/posts/how-to-pass-data-between-iframe-and-parent-window/

@iKlsR
Copy link

iKlsR commented Jan 25, 2021

Thanks! I can use this cleanly in vue embedded via iframe.

@Ranjinisudha
Copy link

how to check parent location path in iframe using postmessage

@FossPrime
Copy link

FossPrime commented Jun 24, 2021

This does not work when the iFrame domain is not the same as the parent.

The general behavior across browsers for cross origin (root domain) iFrames seems to be:

  • iFrame to TopWindow messages ALWAYS work under all circumstances, but the iFrame may have no easy way of knowing the message was received.
  • Messages will work from First Party TopWindow to Third Party domain iFrame
  • Service workers on third party domain iFrames are restricted on Chrome Incognito
    • Don't use service workers for Critical work, use Web Workers directly
  • Third Party domains cannot use ANY local storage API... no exceptions.
    • The only work reasonable work-around is to use a messaging gateway server that Top and Third Party can agree on ahead of time
    • The other option is to exploit Shared Workers and iFrames. third.com/iframe2?payload=[base64] would be loaded on iFrame 2 whenever iFrame 1 needs to receive a response or a message from TopWindow. iFrame2 would then broadcast a window message to all shared worker clients with the payload.

One way to demo this with free services is to use a mix of code sandbox, runkit and glitch... the latter two don't require accounts to use real containers

@ilyalazarev31
Copy link

Many thanks to me this decision saved the nervous system!

@Natanhel
Copy link

Natanhel commented Oct 4, 2021

Does this work on multiple iframes?

@xyal-343448187
Copy link

it's very helpful, thanks.

@Eric-yyy
Copy link

helpful, thanks!

@Reydson
Copy link

Reydson commented Apr 20, 2022

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment