customElements.define( "i-frame", class extends HTMLElement { #shadow = this.attachShadow({ mode: "closed" }); constructor() { super(); this.#shadow.innerHTML = ` `; this.addEventListener("slotchange", this); } handleEvent(evt) { if (evt.type === "slotchange") this.#render(); } get window() { return this.#shadow.querySelector("iframe").contentWindow; } #render() { const iframe = this.#shadow.querySelector("iframe"); if (this.hasAttribute("sandbox")) iframe.sandbox = this.getAttribute("sandbox"); this.ready = new Promise(resolve => (iframe.onload = resolve)); const contents = this.#shadow .querySelector("slot") .assignedElements() .flatMap(el => (el instanceof HTMLSlotElement ? el.assignedElements() : el)) .map(el => el.cloneNode(true)); for (const el of contents) { if (el.tagName === "SCRIPT") el.type = el.type.replace(/^sandbox:/, ""); if (el.tagName === "STYLE") el.type = el.type.replace(/^sandbox:?/, ""); } const body = contents.map(el => el.outerHTML).join("\n"); const lang = this.getAttribute("lang") || "en"; iframe.srcdoc = ` ${body} `; return this.ready; } } );