點燈坊

失くすものさえない今が強くなるチャンスよ

Communication between iframe and the Parent Site

Sam Xiao's Avatar 2021-12-29

If we use <iframe> with other page in different domains. we can use CustomEvent or postMessage to communicate between each other.

Version

HTML 5

CustomEvent

parent -> child

com000

Data is passed from the parent page to the child page.

parent.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
let onClick = () => {
  let detail = 'Hello World'
  let myIframe = document.querySelector('#myIframe').contentWindow
  myIframe.dispatchEvent(new CustomEvent('myEvent', { detail }))
}
</script>
<body>
  <div>
    <span>Parent</span>
    <button onclick="onClick()">Click Me</button>
  </div>
  <iframe id="myIframe" src="child.html"/>
</body>
</html>

Line 16

<div>
  <span>Parent</span>
  <button onclick="onClick()">Click Me</button>
</div>
<iframe id="myIframe" src="child.html"/>

child.html is embedded in <iframe>, and we want to send messages from parent.html to child.html.

Line 9

let onClick = () => {
  let detail = 'Hello World'
  let myIframe = document.querySelector('#myIframe').contentWindow
  myIframe.dispatchEvent(new CustomEvent('myEvent', { detail }))
}
  • Put messages on detail variable
  • Get iframe window by document.querySelector().contentWindow
  • Use new CustomEvent to create a new event and pass an Object with detail property about data
  • Use dispatchEvent to fire event on the child page

child.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
addEventListener('myEvent', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.detail
})
</script>
<body>
  <span>Child : </span><span id="myMsg"/>
</body>
</html>

Line 15

<span>Child : </span><span id="myMsg"/>

Display messages from parent site.

Line 9

addEventListener('myEvent', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.detail
})
  • Use addEventListener on the child page to handle the custom event
  • Use e.detail to get data passed from the parent page

child -> parent

com001

Data is passed from the child page to the parent page.

child.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
let onClick = () => {
  let detail = 'Hello World'
  top.dispatchEvent(new CustomEvent('myEvent', { detail }))
}
</script>
<body>
  <span>Child : </span>
  <button onclick="onClick()">Click Me</button>
</body>
</html>

Line 9

let onClick = () => {
  let detail = 'Hello World'
  top.dispatchEvent(new CustomEvent('myEvent', { detail }))
}
  • Use top.dispatchEvent to fire the custom event on the parent site

parent.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
addEventListener('myEvent', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.detail
})
</script>
<body>
  <div>
    <span>Parent : </span><span id="myMsg"/>
  </div>
  <iframe id="myIframe" src="child.html"/>
</body>
</html>

Line 9

addEventListener('myEvent', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.detail
})
  • Use addEventListener on the parent page to handle the custom event
  • Use e.detail to get data passed by the child page

postMessage

parent -> child

com000

Data is passed from the parent page to the child page but using postMessage.

parent.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
let onClick = () => {
  let myIframe = document.querySelector('#myIframe').contentWindow
  myIframe.postMessage('Hello World', '*')
}
</script>
<body>
  <div>
    <span>Parent</span>
    <button onclick="onClick()">Click Me</button>
  </div>
  <iframe id="myIframe" src="child.html"/>
</body>
</html>

Line 9

let onClick = () => {
  let myIframe = document.querySelector('#myIframe').contentWindow
  myIframe.postMessage('Hello World', '*')
}
  • Get iframe window by document.querySelector().contentWindow
  • Use postMessage to post data directly on the child page, * means all target origins

child.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
addEventListener('message', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.data
})
</script>
<body>
  <span>Child : </span><span id="myMsg"/>
</body>
</html>

Line 9

addEventListener('message', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.data
})
  • Use addEventListener on the child page to handle the message event
  • Use e.data to get data passed from the parent page

child -> parent

com001

Data is passed from the child page to the parent page but using postMessage.

child.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
let onClick = () => top.postMessage('Hello World', '*')
</script>

<body>
  <span>Child : </span>
  <button onclick="onClick()">Click Me</button>
</body>
</html>

Line 9

let onClick = () => top.postMessage('Hello World', '*')

Use top.postMessage to post data directly on the parent site, * means all target origins.

parent.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, init-scale=1.0">
  <title>HTML Lab</title>
</head>
<script>
addEventListener('message', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.data
})
</script>
<body>
  <div>
    <span>Parent : </span><span id="myMsg"/>
  </div>
  <iframe id="myIframe" src="child.html"/>
</body>
</html>

Line 9

addEventListener('message', e => {
  let myMsg = document.querySelector('#myMsg')
  myMsg.innerText = e.data
})
  • Use addEventListener on the parent page to handle the message event
  • Use e.data to get data passed from the child page

Conclusion

  • Creating a custom event is a traditional way to communicate between iframe and the parent site
  • postMessage is new API from HTML 5, which is supported by the modern browser