htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Add Shadow dom support

Open OnurGumus opened this issue 3 years ago • 6 comments
trafficstars

The previous issue is closed but I think it should have been open. So I create this issue Does HTMX work within shadow dom?

Primarily the problem is htmx use document.querySelector to access other elements but that approach won't work when your component is in a shadow dom. Hence the way we access elements should be adjusted.

OnurGumus avatar Aug 04 '22 13:08 OnurGumus

I agree - I would love to use htmx with Shoelace.

But if I do a hx-put or hx-post on an html form, then the html input fields within the Shoelace elements is not found and thus not posted.

rdehuyss avatar Apr 22 '23 08:04 rdehuyss

In case anyone want it, I have a fork here that works with shadow dom. But you need to use alpine as hyperscript doesn't support retriggering https://github.com/OnurGumus/htmx-shadow

OnurGumus avatar Apr 22 '23 08:04 OnurGumus

@OnurGumus Nice! To be clear, do you mean that it needs the alpine morph plugin to work/works with the alpine plugin? Or just that it does not support hyperscript, and that nothing changes for basic use without hyperscript? If it is the latter, then as far as I am concerned it fills an immediate need for me.

At least in theory, HTMX and webcomponent libraries should fit together very well imho, both have a very back-to-html feel to them.

saolof avatar May 02 '23 19:05 saolof

Well the thing is all htmx, hyperscript and alpine rely on observing dom mutations when new code is injected. htmx has processNode and alpine has initTree to manually initiate dom parsing. Since neither can observe behind shadow dom. hyperscript doesn’t have anything like that.

OnurGumus avatar May 03 '23 02:05 OnurGumus

I see that there is also a PR for the fork at #1191 ?

saolof avatar May 03 '23 14:05 saolof

Yes that PR is mine.

OnurGumus avatar May 03 '23 17:05 OnurGumus

Would love to see this supported, any input on what we need to do in order to get this implemented? @alexpetros

zapling avatar Aug 16 '23 09:08 zapling

I agree - I would love to use htmx with Shoelace.

But if I do a hx-put or hx-post on an html form, then the html input fields within the Shoelace elements is not found and thus not posted.

@rdehuyss Check out the shoelace discussion here if you haven't seen it: https://github.com/bigskysoftware/htmx/issues/1323

Would love to see this supported, any input on what we need to do in order to get this implemented?

This has come up before, I think it's just a sufficiently substantial change that it requires thorough review, tests, description etc. #1191 is out of date right now.

alexpetros avatar Aug 16 '23 16:08 alexpetros

Hi @alexpetros - thanks for following up!

Tbh, I've switched to Bulma so it's not a problem for me anymore.

rdehuyss avatar Aug 16 '23 17:08 rdehuyss

Hello, as I said I have working PR. You can also use alpine. Hyper script can’t penetrate the shadow dim. Also using shoelace shouldn’t be a problem. Since you don’t try to penetrate shadow som

OnurGumus avatar Aug 16 '23 17:08 OnurGumus

Thanks for working on a fix and it looks good from my point of view. There are still some people watching this issue! My current workaround is just copying all parent hx-* attributes to a wrapper element in the shadow DOM during construction of the web component and calling afterwards htmx.process on it. I would really appreciate it if we could bring this to the main branch maybe with a feature flag marking it as experimental and not enabled by default for some time.

It would be great if you could resolve the merge conflict @OnurGumus

berlam avatar Aug 19 '23 11:08 berlam

My impression is that owner of this repo has no interest in merging my fork.

OnurGumus avatar Aug 22 '23 11:08 OnurGumus

My impression is that owner of this repo has no interest in merging my fork.

A quick glance at your fork #1191 shows that it currently has merge conflicts, the maintainers will not be able to merge this until those are resolved. Fixing those conflicts is the first step in the merge direction.

I'm sure the maintainers would help you out if you run into any issues getting the fork up-to-date, otherwise we are a few people here that might be able to help.

zapling avatar Aug 22 '23 13:08 zapling

As said there a some time there were no conflicts and there were no interest in merging. Having that said when I have time I will go over it and try to resolve the conflicts. Thanks.

OnurGumus avatar Aug 22 '23 13:08 OnurGumus

Ok I have resolved the merge conflicts.

OnurGumus avatar Aug 22 '23 14:08 OnurGumus

So is hyperscript working with shadow dom or not? I am looking at some web components form IBM Carbon, and I wonder if this will work:

document
  .querySelectorAll('cds-table-row')[0]
  .shadowRoot.querySelector('cds-checkbox')
  .shadowRoot.querySelector('input')
  .click();

hrstoyanov avatar Oct 01 '23 23:10 hrstoyanov

Resolved by #2075, pending 2.0 release

alexpetros avatar Dec 28 '23 15:12 alexpetros

I tried the latest 2.0 release from the commit mentioned in this issue, and it didn't work with my particular scenario. I ended up having to write an extension to account for Shoelace components.

document.body.addEventListener('htmx:beforeRequest', evt => {
    const elements = [
        evt.target,
        ...evt.target.querySelectorAll('*')
    ];

    // loop over elements and add value to evt.detail.requestConfig
    for (const i in elements) {
        const el = elements[i];
        if (el.tagName.startsWith("SL-")) {
            const name = el.name;
            const value = el.value;
            if (name && value) {
                evt.detail.requestConfig.parameters[name] = el.value;
            }
        }
    }
});

I hope this helps folks.

khalidabuhakmeh avatar Jan 11 '24 15:01 khalidabuhakmeh

To be clear, 2.0 is not released yet, even in alpha form. It's a working branch.

alexpetros avatar Jan 11 '24 18:01 alexpetros

@alexpetros Yes. I went to the branch and downloaded the file from the dist folder.

Here's a v2 of the code from above. I didn't account for the disabled key and for checkboxes (shakes fist at checkbox gods).

document.body.addEventListener('htmx:beforeRequest', evt => {
    const elements = [
        evt.target,
        ...evt.target.querySelectorAll('*')
    ];

    for (const i in elements) {
        const el = elements[i];
        const tagName = el.tagName;
        const name = el.name;
        const value = el.value;
        
        // ignore inputs that aren't from shoelace
        if (!tagName.startsWith("SL-")) continue;
        // all inputs can be disabled
        if (el.disabled) continue;
        // the name is required
        if (name === undefined || name === "") continue;
        if (value === undefined) continue;

        // a checkable element
        if (el.checked !== undefined) {
            if (el.checked) {
                evt.detail.requestConfig.parameters[name] = value;
            }
        } else {
            // it is a simple element
            evt.detail.requestConfig.parameters[name] = value;
        }
    }
});

khalidabuhakmeh avatar Jan 11 '24 18:01 khalidabuhakmeh

For some reason Htmx 2 alpha 1 reported shadow DOM support but it didn't work at all with shoelace component library. Just checked HTMX 2 BETA 1 and the shadow DOM is read correctly by Htmx :partying_face:

Shoelace works out of the box now in Htmx. Can't wait for release candidates of version 2!

Minor quirk: If you use shoelace autoloader validation occurs but even when the form is invalid the form is submitted by HTMX. Quite strange but this can be solved using the classic shoelace loader. Will investigate in order to validate if this problem is in Shoelace autoloader or in HTMX.

rsansores avatar Apr 24 '24 02:04 rsansores