bigskysoftware / bigskysoftware/htmx

htmx.process not fully applying HTMX behaviors to elements in shadowDom

Open
#2,454 10 comments 0 reactions 0 assignees View on GitHub
2.0
Dominant language
JavaScript
Stars
49.4k
Forks
1.7k
Avg merge
3d 22h
Merged PRs (30d)
30

Description

I am testing HTMX with web components and have found two issues, which seem to be related to how `htmx.process()` works.

Issue 1:
The `hx-on::before-request` attribute is ignored when using `htmx.process()` as outlined in the docs.
Note that this could be related to https://github.com/bigskysoftware/htmx/issues/2406

Issue 2:
The `hx-get` attribute is ignored when `htmx.process()` is called on a web component that is a child of another web component.

The example code below shows five buttons:
1. Not a component - Created using plain HTML. `hx-get` and `hx-on::before-request` both work.
2. MyComponent - A web component created by following the docs (https://v2-0v2-0.htmx.org/examples/web-components/). `hx-get` works and `hx-on::before-request` does not work.
3. MyComponentAlt - A web component similar to MyComponent, but with `htmx.process(buttonEl)` instead of `htmx.process(root)`. `hx-get` and `hx-on::before-request` both work.
4. MyButton - A simple button web component. `hx-get` and `hx-on::before-request` both work.
5. MyButtonWrapper - A more complex web component, with one web component inside another. `hx-get` does not work (and can't tell if `hx-on::before-request` works).

All five button should behave the same: click to show an alert. Buttons 'Not a component', MyComponentAlt and MyButton all work as expected. MyComponent and MyButtonWrapper do not.

I have tried with both HTMX v1.9.11 and v2.0.0-alpha1, with similar results.

```html


HTMX WebComponents






Not a component







MyButton



button {
cursor: pointer;
}





MyButtonWrapper


window.beforeRequestHandler = (evt) => {
evt.preventDefault();
alert(evt.detail.pathInfo.requestPath);
};

customElements.define(
"my-component",
class MyComponent extends HTMLElement {
connectedCallback() {
const root = this.attachShadow({ mode: "closed" });

root.innerHTML = `
<button
hx-on::before-request="beforeRequestHandler(event)"
hx-get="#my-component"
>MyComponent</button>`;

htmx.process(root);
}
}
);

customElements.define(
"my-compnent-alt",
class MyComponentAlt extends HTMLElement {
connectedCallback() {
const root = this.attachShadow({ mode: "closed" });

root.innerHTML = `
<button
hx-on::before-request="beforeRequestHandler(event)"
hx-get="#my-compnent-alt"
>MyComponentAlt</button>`;

const buttonEl = root.querySelector("button");

htmx.process(buttonEl);
}
}
);

customElements.define(
"my-button",
class MyButton extends HTMLElement {
connectedCallback() {
const root = this.attachShadow({ mode: "closed" });

const content = document
.querySelector(`#my-button-template`)
.content.cloneNode(true);

root.replaceChildren(content);

const url = this.getAttribute("url");

const buttonEl = root.querySelector("button");

buttonEl.setAttribute("hx-get", url);

htmx.process(buttonEl);
}
}
);

customElements.define(
"my-button-wrapper",
class MyButtonWrapper extends HTMLElement {
connectedCallback() {
const root = this.attachShadow({ mode: "closed" });

const content = document
.querySelector(`#my-button-wrapper-template`)
.content.cloneNode(true);

root.replaceChildren(content);
}
}
);

```
I have two questions:
1. Are the docs wrong? Should it be `htmx.process(someElement)` instead of `htmx.process(root)`?
2. Should `htmx.process()` work on nested web components?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.