htmx 4.0 is under construction — migration guide

htmx doesn’t automatically scan inside web components’ shadow DOM. You must manually initialize it.

After creating your shadow DOM, call htmx.process:

customElements.define('my-counter', class extends HTMLElement { connectedCallback() { const shadow = this.attachShadow({mode: 'open'}) shadow.innerHTML = ` <button hx-post="/increment" hx-target="#count">+1</button> <div id="count">0</div> ` htmx.process(shadow) // Initialize htmx for this shadow DOM } })

Targeting Elements Outside Shadow DOM

Selectors like hx-target only see elements inside the same shadow DOM.

To break out:

  1. Target the host element, using host:
<button hx-get="..." hx-target="host"> ... </button>
  1. Target elements in main document, using global:<selector>:
<button hx-get="..." hx-target="global:#target"> ... </button>

Components Without Shadow DOM

Still call htmx.process on the component:

customElements.define('simple-widget', class extends HTMLElement { connectedCallback() { this.innerHTML = `Load` htmx.process(this) } })