Sebb
Motivated by the success @benkimpel had with shoelace (see: Improve Support for Web Components in Forms with "Element Adapters") and the thread by @adw632 (see: Adobe Spectrum 2 web components with LiveView) I tried it myself.
I had some success, but there are also some problems I do not know how to solve and if they are solvable.
Solved? Problem 1 - LV removes attributes set by shoelace
If you do not set all relevant attributes on an element, shoelace sets defaults, LV removes them. This can be easily solved by either wrapping all shoelace elements into function components (see Ben’s thread) or just:
SL_DEFAULTS = {
"SL-BUTTON": { "variant": "default", "size": "medium" },
"SL-AVATAR": { "shape": "circle" },
"SL-BADGE": { "variant": "neutral" },
"SL-ICON": { "library": "default" },
...
}
let liveSocket = new LiveSocket("/live", Socket, {
params: { _csrf_token: csrfToken },
dom: {
onBeforeElUpdated(_from, to) {
const sl_defaults_for_current = SL_DEFAULTS[to.tagName];
if (sl_defaults_for_current) {
Object.entries(sl_defaults_for_current).forEach(([key, value]) => {
if (!to.hasAttribute(key)) {
to.setAttribute(key, value);
}
});
}
}
}
})
this seems to work fine.
Solved? Problem 2 - LV removes state like in @open
Multiple components store their state in an @open, eg <sl-details>
<sl-details summary="Toggle Me">
Lorem ipsum ...
</sl-details>
So when you
- render → closed (
@opennot set) - toggle → opens (
@openset) - rerender → closes (
@openremoved by LV)
This can be fixed by sth like
window.addEventListener("sl-after-show", (evt) => {
liveSocket.execJS(evt.target, '[["set_attr", {"attr": ["open", true]}]]');
})
window.addEventListener("sl-after-hide", (evt) => {
liveSocket.execJS(evt.target, '[["remove_attr", {"attr": "open"}]]');
})
Or sth more sophisticated (see Ben’s thread)
Seems to work fine.
Problem 3 - LV removes elements that shoelace places into the light-DOM
This happens with <sl-breadcrumb>, code:
<sl-breadcrumb>
<sl-icon name="arrow-right" slot="separator" aria-hidden="true"></sl-icon>
<sl-breadcrumb-item>
<sl-icon slot="prefix" name="house"></sl-icon>First
</sl-breadcrumb-item>
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
</sl-breadcrumb>
This is how the breadcrumbs look like after first render (correct):

Note the arrow-icon that shoelace dynamically put into the separator slot of the item:
after a rerender it looks like:

Note the missing arrow-icon:
Problem 4 - LV removes generated classes
happens with <button-group>, code:
<sl-button-group label="Alignment">
<sl-button size="small">Left</sl-button>
<sl-button size="small">Center</sl-button>
<sl-button size="small">Right</sl-button>
</sl-button-group>
first render (correct):

note the classes:
after rerender:
classes missing:

Problem 5 - ARIA
Seems like shoelace puts some important aria attributes which LV removes, didn’t look into that.
Problem 6 - Forms
This does absolutely not work right now, see Ben’s thread.
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming














Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
benkimpel
This is great. Let’s see if we can fix these.
When we were testing it out we found that adding an ID to some of the Shoelace slots helped with patching. It triggers different behavior in morphdom since the id is the
nodeKeyso rather than patching as children it patches directly.There’s a more drastic option as well…
benkimpel
@Sebb if you have a repo where you’re testing stuff I’m happy to help out. I’m benkimpel on github.
Sebb
Wow that’s brutal.
And as far as I understand the problem now, this is the only way (without too much special-case-handling)
I don’t see how LV could ever handle arbitrary WC-libraries that do not follow at least these rules:
Sebb
I made the repo public.
pjode
Here’s the relevant issue in shoelace’s repo. Unfortunately I don’t think this is something that’s going to get addressed
Sebb
That’s easily fixed by the
onBeforeElUpdatedcallback which sets the defaults if not set.cmo
I would’ve thought you’d need a
phx-update="ignore“on the shoelace components that use the light dom/change attributes. What’s the outcome when you use it?Sebb
Sure I could do that and it would be OK for several components.
But what about those that take children?
This would get messy quickly.
benkimpel
Yeah. That’s kind of what i was trying to get at with my element adapter proposal. With WCs that can do anything there has to be some translation layer between what lv is trying to do and how a WC can perform or ignore that operation and we can’t expect the WC author to do so. It’s most obvious in forms right now due to all of the element hardcoding. Aria, light dom mods, and simpler things could be handled in onBeforeElUpdated. It wouldn’t be pretty but it could work.
And sure, we could ignore updates but then the markup rendered from phoenix and passed into a WC is basically static (from phx side) and we have a new set of problems.
This is a tough one and it might just be that lv will only work with very simple WCs.
(I hadnt tested breadcrumbs, btw. Glad you tried that one.)
benkimpel
For example, this fixes the button group…
But how fragile is all of this? idk