DEV Community

Mykolas Mankevicius
Mykolas Mankevicius

Posted on

LiveView + WebComponents = 🚀

I really think LiveView is really amazing.
It has some interop with javascript.
But i think for the most cases the Hooks api is much to overkill.

You need to start managing ids and make sure there are no duplicates even for simple things.

Example a lazy loaded image to be replaced when loaded.

This is a gist of how the hook could look like:

And this is how you would need to use it:

<picture id={@id} alt={@alt} class={@class} style={"--preview-image: url(#{@preview})"} phx-hook="XImage">
  <%!-- truncated... --%>
  <img src={@image} alt={@alt} class="x-image" loading={@loading} />
</picture>
Enter fullscreen mode Exit fullscreen mode

Now it's easy to forget that you need to assign a unique id to a picture, but it's even harder to come up with unique ids for multiple images which are from a same entry. and we're not really using anything from the hook apart from the fact that we need some javascript.

Also the hook only starts working when the livesocket initializes.

So of course there is a better way, enter WebComponents.

and here's how you would use that:

<marko-image>
  <picture alt={@alt} class={@class} style={"--preview-image: url(#{@preview})"}>
    <%!-- truncated... --%>
    <img src={@image} alt={@alt} class="x-image" loading={@loading} />
  </picture>
</marko-image>
Enter fullscreen mode Exit fullscreen mode

And voila, you get the same functionality which starts working as soon as the browser registers the component, you don't need extra attributes to make it work, no ids/no phx-hook.

I've created menus/dropdowns/modals with webcomponents and it's much nicer as the webcomponents api is somewhat nicer to work with.

here's something maybe a bit more interesting a counter for an input:

<x-counter>
  <div class="flex items-center justify-between">
    <label class="flex justify-between">Counter</label>
    <p x-counter-value class="text-xs text-slate-500"></p>
  </div>
  <input type="text" id="counter" class="block w-full rounded-md border" />
</x-counter>
Enter fullscreen mode Exit fullscreen mode

Here's what it looks like:

and here's the code for the web-component:

When i have time i'll write about those components too!

Thank you and have a nice day.

Top comments (2)

Collapse
 
kurt1984 profile image
kurt1984

thanks for the great example! you rock! One question about the web component with liveview, I seeing somewhere says, liveview test cannot work with web component or there are some limitation. what do you think? should we use other testing framework for that

Collapse
 
neophen profile image
Mykolas Mankevicius

Yeah we at marko.ch started using wallaby for some of these things. It's a downside but the UX is worth it!