Skip to content

Web Components (shadow DOM) issue when using HTMX websocket extension #3674

@mawilmsen

Description

@mawilmsen

Problem

The web components pattern from the HTMX documentation works fine for me in regular hx-get/hx-post cases.

I am unable, however, to make it work when using the websocket extension of HTMX for a form, button or any other element. The elements using the ws-send attribute inside the shadow DOM are not triggering any messages. Seems those elements are not properly recognized by the ws-ext extension, even after calling htmx.process(shadow).

Steps to reproduce

A full example with a button in light DOM, triggering properly, and a button in the shadow DOM, not triggering any messages.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/ext/ws.js"></script>
    <title></title>
  </head>
  <body>
    <!-- Button in light DOM triggers messages properly via websocket -->
    <div hx-ext="ws" ws-connect="/ws">
      <button hx-trigger="click" ws-send>WS Light DOM</button>
    </div>

    <!-- Button in shadow DOM doesn't trigger messages via websocket -->
    <div hx-ext="ws" ws-connect="/ws">
      <button-websocket></button-websocket>
      <script>
        window.customElements.define(
          "button-websocket",
          class extends HTMLElement {
            connectedCallback() {
              const shadow = this.attachShadow({ mode: "open" });
              shadow.innerHTML = `<button hx-trigger="click" ws-send>WS Shadow DOM</button>`;
              htmx.process(shadow);
            }
          },
        );
      </script>
    </div>
  </body>
</html>

A regular web component using hx-get/hx-post works just fine, btw. So I assume it's a problem with the websocket extension rather than htmx itself:

<!-- regular hx-get/hx-post trigger in shadow DOM -->
<div>
  <button-regular></button-regular>
  <script>
    window.customElements.define(
      "button-regular",
      class extends HTMLElement {
        connectedCallback() {
          const shadow = this.attachShadow({ mode: "open" });
          shadow.innerHTML = `<button hx-post="/increment">regular</button>`;
          htmx.process(shadow);
        }
      },
    );
  </script>
</div>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions