
Alpine.js: A minimal framework for composing JavaScript behavior in your markup - j4mie
https://github.com/alpinejs/alpine
======
calebporzio
Hi, creator of Alpine here.

Alpine comes out of the server-rendered-app (Laravel/Rails/Django) and static
site context. It's important to recognize that.

To me, Alpine fills a hole in between vanilla JS (or jQuery) and large v-dom
frameworks like Vue/React.

I personally think the complexity/overhead of Vue/React/Etc. doesn't justify
its value in a lot of cases for me. Often, I'm adding simple interactions to
server-rendered pages. Things like dropdowns, modals, dynamic inputs, other
reactive doo-dads...

By using something like Alpine, I get to keep the data-driven reactivity and
declarative template expressions of VueJs, but without all the overhead. (and
without a virtual-dom)

I thought Stimulus would be the framework for me, but I personally felt I was
doing too many manual DOM-manipulations and my code felt more imperative than
I like.

In my opinion, Alpine is unique in these ways:

\- You can use it without maintaining a separate JS file or <script> tag
(although you can easily break code out into separate files and such if you
need to)

\- It doesn't use a virtual-dom at all and uses MutationObserver to react to
DOM manipulations from outside JS (something like Turbolinks, third-party
libs, or your own hand-written JS). This makes it very resilient. It won't
crumble if you touch the real DOM.

\- It's lightweight. It's under 5kb g-zipped.

\- It has a really nice API for listening for and dispatching native browser
Event/CustomEvents rather than using its own event system. This makes it a
really powerful tool for interacting with third-party libs.

It's not a tool for everyone. It's not a Vue or React killer. (although it
might be a Stimulus killer lol)

If it speaks to you, great. You and I are similar.

If not, understandable too. Different tools for different contexts.

Thanks everyone for chiming in!

~~~
mstade
Hey! Cool project, thanks for sharing it with the world!

If I may offer a suggestion, you should perhaps expand on the rationale in the
readme to include some of what you say in this comment. I personally find this
to be a very interesting library for rapid prototyping, so if you're looking
for use cases that's another one for you.

------
lf-non
Pretty much all mainstream frontend libraries have moved away from dom based
templating (or augmenting dynamic behavior through attributes) for good
reason. It simply becomes unmaintainable for anything more complex than basic
interactivity.

This approach can't leverage type systems for javascript (like TS, BS, flow
etc.)

It is easy to end up with mistakes that don't surface as javascript errors and
are swallowed completely.

You hit weird quirks when browser injects additional nodes (eg. tbody in
tables) or restructures invalid markup (eg. div inside p).

Ostensibly this approach would help with progressive enhancement, but too
often careless usage results in flashes of broken UI which would then fix
themselves when javascript kicks in. Then you need hacks to circumvent those
with hacks like ng-cloak.

Also, in an ideal world this would help with handoff when working with web-
designers who are familiar with only html/css but that rarely happens in
practice. Every time a web-designer rearranges things in the dom hierarchy the
parent-child associations break and that again needs comprehensive testing.

Having worked with applications written using knockoutjs as well angular 1
(both of which used similar approaches) which organically grew over multiple
years and (to put gently) didn't age gracefully, I wouldn't recommend this
approach to anyone.

If you can't (or don't want to) go down the road of a full SPA but do want to
build interactive applications with non-trivial amounts of javascript, lit-
element [1], Vue [2], Strudel [3] and SPF [4] are much better solutions.

[1] [https://lit-element.polymer-project.org/](https://lit-element.polymer-
project.org/)

[2] [https://vuejs.org/](https://vuejs.org/)

[3] [https://strudeljs.org/](https://strudeljs.org/)

[4] [https://github.com/youtube/spfjs](https://github.com/youtube/spfjs)

~~~
rolae
Alpine.js really was created for javascript sprinkles, where even vue.js might
be overkill. For example, if you have an app, but you need to have dropdowns
and modals. Then something like alpine.js can be nice.

So it is actually not intended for things more complex than basic
interactivity. And what you build with it, should be simple enough you don't
need any type system.

For people interested, there is a good episode on FullStackRadio on the topic
[http://www.fullstackradio.com/132](http://www.fullstackradio.com/132)

~~~
kreetx
What about Svelte as a light-weight framework -- it compiles itself out (there
is no library included in the final app).

~~~
ratww
Svelte is great but requires a compilation step, which is probably the kind of
complexity that potential users of Alpine.js are trying to avoid.

------
AlchemistCamp
To anyone feeling a desire to reflexively dismiss Alpine.js, I'd _strongly_
suggest taking an hour or two rewriting a toy project that uses Stimulus JS
into Alpine and give it a fair comparison.

If you haven't ever used Stimulus, then I'd be doubly cautious about making a
snap judgement. If you're the type who writes every single site as a SPA, then
this library isn't for you.

Alpine is gaining traction quickly in the Laravel world and isn't going to be
disappearing in the near future. On the contrary it's likely to expand and
gain adoption in other MVC framework ecosystems. I, for one, am seriously
considering for my next Phoenix project.

~~~
mands
We're currently using a combination of Intercooler, Stimulus, and React
components in our MPA depending on the interactivity and complexity needs of
each component in question - so we're certainly not in the SPA camp.

However having listened to the Full Stack Radio episode and trying Alpine out,
I'm not convinced on writing interdependent JS fragments in HTML attributes.

For our team Stimulus feels more robust - store state in the DOM, which then
calls full JS/TS classes to do the computation - keeping the separation of
concerns intact. We can also make use of Typescript typing, linting, and
bundling of our Stimulus controllers, and test the behaviour more easily.

Exciting to see more options in the non-SPA world tho!

------
warpech
Looks similar to Basecamp's Stimulus[0], with a pinch of original AngularJS
1.x[1]. Care to explain the differences?

[0][https://stimulusjs.org/](https://stimulusjs.org/)

[1][https://angularjs.org/](https://angularjs.org/)

~~~
rolae
While the spirit of using a simple library for javascript sprinkles to enahnce
your app is similar, stimulus.js and alpine.js are quite different:

Alpine.js has the x-data property, to keep state that you can manipulate, in
stimulus all state is directly in the DOM. So for example to make a modal with
stimulus, you would add a class to show a hidden overlay. In Alpine you would
use a x-show property, that reacts to a change in the data of the component.

So the big difference is that alpine has a reactive data context as a first
class citizen. In a way it is actually much more similar to AngularJS 1.x than
to stimulus, with the idea that it is really intended only to be used to
enhance existing html, not to build whole apps with it.

------
gitgud
Interesting, I like the _HTML-first_ attitude and the quote "Think of it like
Tailwind for JavaScript.".

It's also amazing how fast the [1] demo is, I forget how fast webpages can be
without Javascript rendering the HTML...

~~~
ehnto
I don't think it's even the fault of the JS frameworks rendering time, it's
all the network latency between asynchronous requests and assets loading in
that makes modern websites feel janky.

------
continuational
How does this compare to Intercooler.js?

[https://intercoolerjs.org/](https://intercoolerjs.org/)

~~~
hombre_fatal
Having used Intercooler a few times now, it feels like the worst of all worlds
since you now have to write and return HTML at AJAX endpoints and keep that
HTML synced with the rest of your HTML (e.g. consider CSS) instead of just
returning data from an API endpoint.

You end up with a bunch of made-for-Intercooler endpoints instead of
thoughtful, general, data API endpoints.

~~~
mands
We're using intercooler on our current site and find it easier to keep the API
side of the application separate from the HTML-generating MPA side.

Internally they both call out to common code, but we like to keep the API-side
RESTful and aren't so concerned about REST for the HTML side, both the full
page views and intercooler-specific partials.

------
strogonoff
On the other hand, if you are not opposed to converting to React in the long
run[0], but it looks too complex for merely adding some interactivity to a
page: it can be simple to incorporate just a few widgets with it, a fact
somewhat obscured by extensive documentation.

For a minimal start there’s no need to adopt JSX, wrap your head around hooks
and functional components, or deal with Webpack configuration. Just add
ReactDOM and React scripts, alias React.createElement() to something short
like el() for use in render() methods, compose your components and render them
at the desired root if user agent has JavaScript enabled[1].

You have the freedom to move the whole page to React later, implement server-
side rendering and so on, but you don’t have to.

That said, yes, you will be pulling React, which will consume extra bandwidth,
and to stay crawler-friendly your React components ideally should replace and
improve functionality already provided by the static page in a more basic way.

[0] Perhaps you can see your application growing complex enough and you
suspect React would be easy to hire for if you need additional help, etc.

[1] To preserve compatibility with older browsers but write components as
modern classes, you could add a simple frontend build step that runs Babel on
JS files with a single preset "@babel/env" specifying your target browsers.

~~~
dragonwriter
> For a minimal start there’s no need to adopt JSX, wrap your head around
> hooks and functional components, or deal with Webpack configuration.

Unless you've already learned React with class components and lifecycle
methods, I suspect it simpler to just not learn them and learn functional
components and hooks. It's extra stuff to wrap your head around if you learned
the old way first, sure, but it's not fundamentally more complex on its own.

~~~
Scarbutt
_I suspect it simpler to just not learn them and learn functional components
and hooks._

The official react docs and tutorial don't help here since it introduces class
components first.

------
mnoga23
Looks like client side scriplets - html(structure) mixed up with
code(behavior). Can lead to spaghetti code just like it did in the old days
(pre JSP) on server side java.

~~~
AlchemistCamp
That's remarkably similar to what I heard people saying about React in 2014.

~~~
root_axis
The criticism isn't really accurate for react though. React only mixes markup
and code in the sense that markup is produced through function calls rather
than as the result of processing arbitrary strings.

------
arturogoosnargh
Seems useful for interactivity on sites using static site generators like
Jekyll.

~~~
julvo
That plus server-side web app frameworks like rails, Django etc.

------
Hitton
I don't see too many situations when using this and saving few KBs is worth it
over using full featured Vue.js.

------
nine_k
If your page logic is small and trivial, anything goes. This thing, svelte,
knockout, even jQuery, even bare JavaScript event handlers.

As your logic grows, you need a one-way binding to preserve the app's
maintainability and your sanity. Hence React (normally with Redux), Mithril,
cycle.js, Elm, etc.

------
codedokode
What an awful idea:

\- first, it is not obvious whether an attribute affects something or not. How
are you supposed to know what this or that attribute does?

\- second, if you made a typo, there is no error messages

\- third, no there is no namespaces and attributes can conflict with
attributes from other libraries

What's wrong with good old inline event handlers like onclick? With them you
can just click a called function name and see its source.

~~~
whoisjuan
> What's wrong with good old inline event handlers like onclick? With them you
> can just click a called function name and see its source.

I haven't read the source of Alpine but I'm assuming the inline declarations
are abstractions that are moved out of the DOM execution context and therefore
can be cached. Real inline event handlers will actually be evaluated and
executed in every page load, which will affect performance, especially with
inside loops.

