Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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>
@iinviisiible
Copy link

iinviisiible commented Jun 8, 2019

Thanks for this great live example.
As a security guy, I would add that the message part should be escaped/sanitized (ex: json data should be JSON.parsed) before it's sent to output. also, the origin should be specified by the sender to not disclose any sensitive data to third-party domains and it should be verified by the receiver (event handler) to accept msgs from trusted domains only.

example

@jessemoon0
Copy link

jessemoon0 commented Jun 25, 2019

Amazing Gist, thank you!

@laurent-d
Copy link

laurent-d commented Jul 1, 2019

Thanks a lot for this !!

@jaimecalvo81
Copy link

jaimecalvo81 commented Jul 26, 2019

Awesome example, thanks a lot

@Kanika1994
Copy link

Kanika1994 commented Aug 7, 2019

Thanks !
Its very useful ..

@sebas932
Copy link

sebas932 commented Aug 14, 2019

Great! was very useful for me.

@SokolskyNikita
Copy link

SokolskyNikita commented Aug 15, 2019

I've created a cross-domain example based on @pbojinov's great demo to show that this also works for cross domain iframes.

@kanachrisi
Copy link

kanachrisi commented Aug 20, 2019

Thanks a lot my friend!!

@dorelljames
Copy link

dorelljames commented Aug 22, 2019

Thanks, man. Huge help with what I'm doing right now. Daamn works! 😊

@plann9
Copy link

plann9 commented Aug 24, 2019

Works great with a div or textarea as the receiving element but it won't pass the data to a text input box. Can you help?
ex: <input type="text" id="results"> does NOT work
ex: <div id="results"> does work

@lucas1
Copy link

lucas1 commented Sep 7, 2019

Thanks :)

@codebyarbaz
Copy link

codebyarbaz commented Sep 9, 2019

Thanks man..!

@gjrmacedo
Copy link

gjrmacedo commented Sep 16, 2019

Thank you!

@camjcorley
Copy link

camjcorley commented Oct 10, 2019

Just dog-piling on top of all these thankful people to say this was very helpful for me as well. Thank you for sharing!

@justenh
Copy link

justenh commented Dec 5, 2019

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

@Christopher-Hayes
Copy link

Christopher-Hayes commented Jan 7, 2020

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

@ChandanaRDeshmukh96
Copy link

ChandanaRDeshmukh96 commented Mar 6, 2020

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

leotengfei commented Apr 15, 2020

Thank you,very useful!

@justlester
Copy link

justlester commented Jun 19, 2020

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

mrvisser commented Jun 23, 2020

@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

Ranjinisudha commented Jun 24, 2021

how to check parent location path in iframe using postmessage

@MarsOrBust24
Copy link

MarsOrBust24 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

ilyalazarev31 commented Jul 16, 2021

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

xyal-343448187 commented Oct 13, 2021

it's very helpful, thanks.

@Eric-yyy
Copy link

Eric-yyy commented Jan 17, 2022

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