JSFiddle - React, Tailwind, and code Playground
HTML
<my-context id="foo">
<div>
<my-context id="bar">
<div>
<my-el>
<output>Click button for updates</output>
</my-el>
</div>
</my-context>
</div>
</my-context>
<br>
<button data-context-id="foo">Increase foo</button>
<button data-context-id="bar">Increase bar</button>
JavaScript
// base class for components wanting to get context change updates
class ContextAwareHTMLElement extends HTMLElement {
* #findContexts() {
let context
let target = this
while (target && (context = target.closest('my-context'))) {
yield context
target = context.parentNode
}
}
connectedCallback() {
for (const context of this.#findContexts()) {
context.addEventListener("context:change", event => {
this.contextChangeCallback(event.target)
})
}
}
contextChangeCallback(context) {}
}
// example component getting updates from context
customElements.define('my-el', class extends ContextAwareHTMLElement {
contextChangeCallback(context) {
this.querySelector("output").value = `Context change: ${context.id} = ${context.value}`
}
})
// context component which dispatches change events with value changes
customElements.define('my-context', class extends HTMLElement {
#value = 0
get value() {
return this.#value
}
set value(value) {
this.#value = value
this.dispatchEvent(new Event("context:change"))
}
})
// hook up buttons to change context values
for (const button of document.querySelectorAll("button[data-context-id]")) {
button.addEventListener("click", () => {
document.getElementById(button.dataset.contextId).value++
})
}