PETL stack - is AlpineJS still relevant?

Now that LiveView 1.7 has JS commands, is AlpineJS still relevant?

1 Like

Isn’t LiveView.JS just for very basic stuff like temporarily setting a class?
Don’t see how you implement more involved things like drag+drop for example.

Still I think its great, covers just what I’m missing with my node and npm and webpack free cdn-css setup.
(Assuming I do not need those beasts with LiveView.JS, didn’t try it yet)

1 Like

I personally find hooks easier to work with than Alpine, although that might just be an experience thing. Phoenix JS bindings look good, but haven’t tried them myself yet.

I think that tailwind shipping Alpine bindings will keep it relevant for the time being, otherwise you’ll be writing implementations yourself.

1 Like

Alpine can be used for more than just that?? I should maybe give it a closer look… but I’m otherwise I’m with @sb8244 and prefer to write hooks anything more complex than setting classes (I actually just use hooks for everything… in my so far limited use of LiveView).

I find the alpine/liveview interaction for non-trivial things a bit convoluted, i.e. keeping the state in sync, and will replace it with js commands, hooks and custom Web components.

I never like the term of PETAL. My stack is Erlang, Elixir, Phoenix, Liveview and Surface, one built on top of the previous one, EEPLS or SLEEP if we need to make it pronounceable. TailwindCSS and AlpineJS are nice additions but they are tangential and replaceable.


Nice perspective @derek-zhou - I myself feel a lot of unease with the sheer verbosity of tailwindcss - specially - many a times it hides the purpose of the view at first glance. A bootstrap sort of framework without Javascript might be a very good value for application developers like me who are not professional UI developers. Yeah - may be Bulma - hope something comes to fill this space.

Pardon that this may be an uninitiated thought, but isn’t there still a need for Alpine for doing things outside of the LiveView?

I’m looking at structuring a “live app” (as McChord proposed naming them) from Tailwind UI templates I bought license to. There you have a sidebar which must be closed upon the user clicking the cross when not on desktop size.

Sure you can try Alpine for that. Might not work out so well if you’re pushing stuff from the server into that sidebar when you show it though. I trigger my show from the server for the sidebar for this reason.

Why would you choose Alpine over JS Commands for something like that though?

sure, you can do anything with alpine (I think, not a webdev).

To me it’s not really clear what the limitations are for LiveView JS. What can be done? What is reasonable to do with LV-JS, where do you better use another tool. Would love to see some examples.

Have you watched the LV and Web Compoenents talks from ElixirConf2021?


I started considering Alpine since I was looking at having a sidebar defined in the live template. At the stage where I just try to lay things from the Tailwind UI application skeleton template out. I tried invoking JS and got an error since it won’t be available outside of the LiveView.

Guess this will make me end up with liveviews for each page with two live_sessions, one for users and one for administration. Then navbars are templated components loaded with each mount of the LVs.

Would be amazing with an insightful blogpost on this (I’m not insightful enough unfortunately, maybe in due time).

*prefer to achieve this without Surface if possible

The Web Component talks covers my case entirely, many thanks @cmo :clap:t2:

Didn’t know it covers LiveView.JS. I’ll check it out.
So far the best source I know is the keynote from Chris McCord.

EDIT: LV.JS is not covered, still a great talk, but too much JabbaScript for me. :yum:

For Phoenix 1.5, AlpineJS is the simplest solution for managing client-side state changes that might be overwritten by server-side events, e.g. whether a nav is open or the scroll position of a text view/chatbox (things that in most cases should not be handled server-side).

If you’re triggering UI changes with JS in elements nested with elements that need to receive server-side updates, adding phx-update="ignore" is not a solution in 1.5 as the elements in that tree that do need server-side updates will not get them.

I resisted AlpineJS at first and came up with a bespoke solution… but that was an absolute waste of time. I eventually spent 20 minutes to learn AlpineJS and it was well worth it, as AlpineJS’s attribute variables/events are super simple and mesh perfectly with the way LiveView behaves.

AlpineJS is way simpler and better than vanilla JavaScript for client-side UI stuff, but to set it up you do have to add webpack config, which understandably upsets devs who don’t want to sift through outdated docs about webpack config. (Protip: Always add the year and webpack version when searching for webpack config guides. Changes to webpack config year to year are almost always breaking ones.)

I haven’t had the time to check out LVJS (I have Phx 1.5 in production, tbh I wait until a couple minor version releases after major ones to adopt upgrades with so many changes :P) so I don’t know if AlpineJS is unnecessary with the latest and greatest.

1 Like

Tailwind classes get pretty ugly if you’re making cards and stuff like that, but I love the text sizing and typography helpers, they save sooo much time in creating properly responsive mobile text sizes, truncation, etc… so easy to make slick mobile web apps without so many manual media queries


I don’t think it’s time to get rid of AlpineJS just yet, because you can use it to do client-side tasks also on regular controllers.

Say, you have an interface with tabs – doing those in Alpine will avoid any latency from the server and make your UI snappier.
Another big thing where I’ve found it useful, for example, is handling timezones. Doing that server-side would be an absolute pain - ask users for their timezone, and whenever you have a datetime, convert it. And then you’d also have to deal with localization.

AlpineJS to the rescue: You can have localized datetime displays and inputs with minimal effort - both in LiveViews and regular controllers:


Hi. There is no comment section on your blog so I’m going to write it here.
I have been using your excellent AlpineJs trick for a week:

<div x-data="{date: new Date($el.innerText)}" x-text="date.toLocaleString()" >
  <%= @starts_at %>

But I noticed a very big problem - sometimes the LiveView will render with the datetime displayed as "Invalid Date".
I believe this happens sometimes because of LiveView being rendered twice, and the element’s inner text having already been transformed to localized time string (and so can no longer be parsed to valid JS Date).
Anyway, I have found this solution to be more robust, albeit ugly:

<div x-data="{get localisedDateTimeString() {
               d = new Date($el.innerText);
               if(d instanceof Date && !isNaN(d)) {
                 return d.toLocaleString();
               } else {
                 return $el.innerText;
     x-text="localisedDateTimeString" >
  <%= @starts_at %>

In this, I am attempting to parse the date and, if it fails, I just return the pre-existing innerText.

This solution is so ugly that I put the HTML into its own LiveComponent that just accepts a date and a class assign.

I hope this helps somebody else facing the "Invalid Date" bug. :slight_smile:

relevant SO post: Detecting an "invalid date" Date instance in JavaScript - Stack Overflow

1 Like

how about:

  x-data="{date: new Date($el.dataset.time)}"
  data-time={@starts_at} />

That is much much better. Thanks!