Cross-Origin Communication Between Parent Window and Iframe

Two primary approaches are available for exchanging data betweeen a parent window and an embedded iframe. The first relies on direct access via contentWindow when both documents share the same origin; the second uses the standard postMessage API to handle cross‑origin scenarios.

1. Communication via contentWindow

  • TypeScript declaration file
declare global {
  interface Window {
    recvFromParent?: (message: string) => void
    recvFromChild?: (message: string) => void
  }
}

export {}

  • Parent window (Vue component)
<template>
  <div>
    <button @click="transmitToChild">Parent Button</button>
    <iframe
      style="display: block; width: 100%; height: 600px"
      ref="frameEl"
      src="/child.html"
      frameborder="0"
    ></iframe>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const frameEl = ref<HTMLIFrameElement>()

    const transmitToChild = () => {
      // Must be same origin
      frameEl.value?.contentWindow?.recvFromParent?.('Parent says hello to child')
    }

    window.recvFromChild = (message) => {
      console.log(message)
    }

    return {
      frameEl,
      transmitToChild
    }
  }
})
</script>

<style lang="scss" scoped></style>

  • Child window (plain HTML)

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Child Window</title>
  <style>
    html, body {
      height: 100%;
    }

    body {
      margin: 0;
      background: #cccccc;
    }
  </style>
</head>
<body>
<button onclick="transmitToParent()">Child Button</button>
<script>
  window.recvFromParent = (message) => {
    console.log(message);
  };

  function transmitToParent() {
    window.parent.recvFromChild?.("Child says hello to parent");
  }
</script>
</body>
</html>

2. Communicatino via postMessage

  • Parent window (Vue component)
<template>
  <div>
    <button @click="sendMessageToChild">Parent Button</button>
    <iframe
      style="display: block; width: 100%; height: 600px"
      ref="frameEl"
      src="http://localhost:3000"
      frameborder="0"
    ></iframe>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const frameEl = ref<HTMLIFrameElement>()

    const sendMessageToChild = () => {
      // Works across different origins
      frameEl.value?.contentWindow?.postMessage(
        { payload: 'Parent says hello (cross-origin)' },
        '*'
      )
    }

    window.addEventListener('message', function (event) {
      console.log('Parent received', event)
    })

    return {
      frameEl,
      sendMessageToChild
    }
  }
})
</script>

<style lang="scss" scoped></style>

  • Child window (plain HTML)

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Child Window</title>
  <style>
    html, body {
      height: 100%;
    }

    body {
      margin: 0;
      background: #cccccc;
    }
  </style>
</head>
<body>
<button onclick="sendMessageToParent()">Child Button</button>
<script>
  window.addEventListener("message", function(event) {
    console.log("Child received", event);
  });

  function sendMessageToParent() {
    window.parent.postMessage({ payload: "Child says hello (cross-origin)" }, "*");
  }
</script>
</body>
</html>

Tags: iframe postMessage contentWindow Cross-Origin Vue.js

Posted on Mon, 02 Nov 2026 16:45:19 +0000 by aahh