Last active
September 16, 2022 07:36
-
-
Save jaredcwhite/2dbab990e8d38446da6a866d8921ce6d to your computer and use it in GitHub Desktop.
Attaching shadow roots on Turbo events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function attachShadowRoots(root, callback = null) { | |
const shadowNodes = [] | |
root.querySelectorAll("template[shadowroot]").forEach(template => { | |
const node = template.parentNode | |
shadowNodes.push(node) | |
const mode = template.getAttribute("shadowroot") | |
const shadowRoot = node.attachShadow({ mode }) | |
shadowRoot.appendChild(template.content) | |
template.remove() | |
attachShadowRoots(shadowRoot).forEach(childNode => shadowNodes.push(childNode)) | |
}) | |
if (callback) { | |
shadowNodes.forEach(node => callback(node)) | |
} else { | |
return shadowNodes | |
} | |
} | |
document.documentElement.addEventListener("turbo:load", (event) => { | |
attachShadowRoots(event.target, node => node.attachedShadowRootCallback?.()) | |
}) | |
document.documentElement.addEventListener("turbo:frame-load", (event) => { | |
attachShadowRoots(event.target, node => node.attachedShadowRootCallback?.()) | |
}) | |
document.documentElement.addEventListener("turbo:before-stream-render", async (event) => { | |
const prevRender = event.detail.render | |
event.detail.render = (async (newElement) => { | |
await prevRender(newElement) | |
event.target.targetElements.forEach(el => { | |
attachShadowRoots(el, node => node.attachedShadowRootCallback?.()) | |
}) | |
}) | |
}) |
Here's an even nicer way to do it using Promises and a mixin:
const DSDOM = (superClass) => class extends superClass {
#shadowRootConnected;
attachedShadowRootCallback() {
this.#shadowRootConnected()
}
get shadowRootAttached() {
if (this.shadowRoot) return Promise.resolve()
const promise = new Promise(resolve => this.#shadowRootConnected = resolve)
return promise
}
}
class TestDsd extends DSDOM(HTMLElement) {
async connectedCallback() {
await this.shadowRootAttached
console.log("I'm attached!", this.shadowRoot.innerHTML)
}
}
customElements.define("test-dsd", TestDsd)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How this would work in practice for an element: