DEV Community

Farzad YZ
Farzad YZ

Posted on • Originally published at farzadyz.com

Cross-Domain Iframe-parent communication

There are many cases iframe would be a good solution to use. Although they are kind of dead to HTML and not a lot of developers use it, It could come up to you as a solution to a complicated problem some day.

Knowing a way to communicate through an iframe to parent is such a valuable and time saver. Maybe iframe could tell it’s parents when it’s content is ready or engage user interactions inside an iframe with the parent to react properly.

Some days ago at my company, we had a Wordpress website that loaded an iframe for choosing a plan to buy virtual machines as shown below.

https://cdn-images-1.medium.com/max/1600/1*Npna_TbF8ChgAroSVkyu_Q.png

I was assigned a task to do something challenging on this element. The company intended to open a URL on click of the orange button, BUT because the button was inside the iframe, that couldn’t be managed easily.

First thing I tried to was to use postMessage to send a message from iframe to its parent. I came up with this code:

<iframe src="Path/To/Html"><button id="my-btn">Start</button></iframe>
Enter fullscreen mode Exit fullscreen mode
document
  .getElementById("my-btn")
  .addEventListener("click", handleButtonClick, false);
function handleButtonClick(e) {
  window.parent.postMessage("iframe_message");
}
Enter fullscreen mode Exit fullscreen mode

And also listen to the message on the parent window:

window.addEventListener('iframe_message', function() {
window.open('some url', '_blank')
}, false
Enter fullscreen mode Exit fullscreen mode

It was perfect! worked like a charm. It passed some minutes until I figured out the actual problem. This only worked for same-domain iframes. Apparently, cross-domain iframes don’t post message to the parent properly.

I dogged the web a lot and found a really interesting inspiration on a dark edge of stackoverflow. Although It did not help me, It fixed me in the right direction. The solution was to use customEvents.

So I refactored the solution to:

document
  .getElementById("my-btn")
  .addEventListener("click", handleButtonClick, false);
var myEvent = new CustomEvent("my_event", { detail: { url: "some url" } });
function handleButtonClick(e) {
  window.parent.dispatchEvent(myEvent);
}
Enter fullscreen mode Exit fullscreen mode

And listen to it on the parent of course:

window.addEventListener(
  "iframe_message",
  function(e) {
    var url = e.detail.url;
    window.open(url, "_blank");
  },
  false
);
Enter fullscreen mode Exit fullscreen mode

It was amazing as I could easily pass custom data from iframe to the parent window.

Conclusion

Dealing with iframes is Hard. It’s not intended to be used unless there is no other way to do it.

If you’re using a same-domain iframe, you’re in heaven. You could easily control iframe’s content and also communicate to its parent through postMessage.

But you’re in Hell when it gets cross-domain. You could only use CustomEvent and dispatchEvent on the iframe and listen to it on the parent window. In this case, try to modularize your communication protocol and pass custom data.

Top comments (1)

Collapse
 
asimen1 profile image
Asaf

iframes shouldn't be hard :) I'm not sure why you ran across an issue doing postMessage cross-domains, but it's definitely not true that "cross-domain iframes don’t post message to the parent properly". In fact - quite the opposite, postMessage was designed to facilitate cross-domain messaging!

In any case I wrote a library that will make your life easier next time - it’s called iFramily (github.com/EkoLabs/iframily). Basically it has a simpler API than postMessage, which includes Promise-based responses, message queuing, and managing the connection until both frames are ready to talk. It also takes a responsible approach to security...

Would love to hear your thoughts!