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++
  })
}