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:
- Target the host element, using
host:
<button hx-get="..." hx-target="host"> ... </button>
- 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) } })