This part of the library helps you to communicate with helper page iframes. It comes with methods to alter the iframe's content and receive size updates.
| Term | Explanation |
|---|---|
| Host message | A message sent from the host page to the helper page iframe. |
| Iframe message | A message sent from the helper page iframe to the host. |
Attention: The helper page html generated by the server side code comes with some head tags (title, meta) and a JS script tag in the body.
All "set content" commands will be handled by the helper page in such a way, that all tags that the helper came with are preserved. When you send a "set content" command again, the head or body will be reset to the set of tags the helper page was delivered with.
You must send "set content" commands after the iframe has loaded.
You can use the method sendSetHeadContentMessage to append content to the
iframe's <head> tag.
import {sendSetHeadContentMessage} from "@perspective-software/cross-origin-html-embed"
const iframe = document.querySelector("iframe#html-embed")
iframe.onload = () => {
sendSetHeadContentMessage(
iframe,
`
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://necolas.github.io/normalize.css/latest/normalize.css">
`
);
}
iframe.src = "https://sandbox.myservice.com"You can use the method sendSetBodyContentMessage to append content to the
iframe's <body> tag.
import {sendSetBodyContentMessage} from "@perspective-software/cross-origin-html-embed"
const iframe = document.querySelector("iframe#html-embed")
iframe.onload = () => {
sendSetBodyContentMessage(
iframe,
`
<h1>Pickle Rick</h1>
<script>
console.log("Pickles are delicious. But not, if they could be Rick.");
</script>
`
);
}
iframe.src = "https://sandbox.myservice.com"The two set content methods outlined above share the same options.
The first argument is necessary to send the message to the correct destination. You need to pass the iframe element.
Internally the methods obtain the targetOrigin used for the postMessage
communication from the iframe src.
You can override the targetOrigin via the third optional options parameters.
Method parameters:
| Parameter | Required | Description |
|---|---|---|
| iframe | yes | Iframe to sent message to. |
| content | yes | HTML to be appended to the iframe's <head>. |
| options | Optional options object. You can pass target origins explicitly via { targetOrigins: string[] }. |
Theoretically you can also use the underlying method sendHostMessage to send messages
to the helper page iframe.
This method is used by the "send (head|body) content" methods explained above.
We won't go into more details here, as there are the abstraction methods. In case
you still want to use sendHostMessage, the TypeScript types and comments should answer all your questions.
We advise you to call "receive" methods once the iframe has loaded/has a src.
This is important for automatically obtaining the origin to listen for messages from.
Use the method receiveIframeDimensionsUpdates to listen for any dimensions updates
the helper page iframe sends to the host.
This allows you to size the iframe element so that the complete content is shown.
import {receiveIframeDimensionsUpdates} from "@perspective-software/cross-origin-html-embed"
const iframe = document.querySelector("iframe#html-embed")
iframe.onload = () => {
receiveIframeDimensionsUpdates(iframe, (message) => {
iframe.style.height = `${message.data.documentElementHeight}px`;
})
}
iframe.src = "https://sandbox.myservice.com"You can also unregister underlying message event listeners. The method
returns a function. When you call the function, the message reception is stopped.
import {receiveIframeDimensionsUpdates} from "@perspective-software/cross-origin-html-embed"
// ...
let stopDimensionUpdatesReception: (() => void) | null = null;
iframe.onload = () => {
stopDimensionUpdatesReception = receiveIframeDimensionsUpdates(iframe, (message) => {
iframe.style.height = `${message.data.documentElementHeight}px`;
})
}
// ...
// Embed teardown
stopDimensionUpdatesReception?.();
iframe.remove();| Parameter | Required | Description |
|---|---|---|
| originOrIframe | yes | Used for listening to messages of the correct origin. Iframe, or explicit targetOrigin(s) as string or Array of strings. If you pass an iframe, the library checks that event.source === iframe.contentWindow. You can change this via the options. |
| callback | yes | Callback to be executed on message reception. |
| options | You can change the iframeEmitterCheck mode. The mode strictSourceCheck (default) checks that event.source === iframe.contentWindow. The mode sourceOrOriginCheck additionally checks if event.origin matches the iframe's src. |
It might be necessary to reset the iframe height to 0px when
you set new body content.
Otherwise, you might have too much whitespace. Why? Because the new content may be smaller than the previous content and thus doesn't cause any iframe content size changes. This way your host does not get the new actual content size.
Similar to the send methods, you can theoretically also use
the underlying base method receiveIframeMessages.
Currently, it does not make any difference, as there is only one type of iframe messages.
We advise you to use the method receiveIframeDimensionsUpdates
as it provides more precise types.
Check out also the vanilla JS example directory that is connected to the backend examples: Vanilla JS Code Example 🔗
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vanilla JS example</title>
</head>
<bod>
<textarea id="custom-html"></textarea>
<iframe id="custom-html-sandbox"></iframe>
</bod>
</html>Your JavaScript/TypeScript:
import {receiveIframeDimensionsUpdates, sendSetBodyContentMessage} from "@perspective-software/cross-origin-html-embed"
const textarea = document.querySelector("textarea#custom-html");
const iframe = document.querySelector("iframe#custom-html-sandbox");
iframe.onload = () => {
receiveIframeDimensionsUpdates(iframe, (message) => {
iframe.style.height = `${message.data.documentElementHeight}px`;
})
textarea.addEventListener("change", (event) => {
sendSetBodyContentMessage(iframe, event.target.value);
})
}
iframe.src = "https://sandbox.myservice.com"Check out also the React example that is connected to the backend examples: React Code Example 🔗
import { useEffect, useRef, useState } from "react";
import {
receiveIframeDimensionsUpdates,
sendSetBodyContentMessage,
} from "@perspective-software/cross-origin-html-embed";
export default function HtmlSandboxEmbed({ html }: { html: string }) {
const iframeRef = useRef<HTMLIFrameElement | null>(null);
const [iframeLoaded, setIframeLoaded] = useState(false);
const [iframeHeight, setIframeHeight] = useState(0);
useEffect(() => {
if (iframeRef.current) {
return receiveIframeDimensionsUpdates(iframeRef.current, ({ data }) => {
setIframeHeight(data.documentElementHeight);
});
}
}, []);
useEffect(() => {
if (iframeRef.current && iframeLoaded) {
sendSetBodyContentMessage(iframeRef.current, html);
}
}, [html, iframeLoaded]);
return (
<iframe
id="custom-html-sandbox"
src="http://localhost:4042"
ref={iframeRef}
onLoad={() => {
setIframeLoaded(true);
}}
style={{ height: `${iframeHeight}px` }}
/>
);
}