Hacker News new | past | comments | ask | show | jobs | submit login
Alpine.js: A minimal framework for composing JavaScript behavior in your markup (github.com)
148 points by j4mie 12 days ago | hide | past | web | favorite | 47 comments





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!


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.


The benefits sounds, would it work with Typescript?

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/

[2] https://vuejs.org/

[3] https://strudeljs.org/

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


I'm not the author and I've never used this library, but I think your comment is unnecessarily dismissive anyway. You're not necessarily wrong, but I feel there's ample room in the space between wanting to hack something together and built according to this week's best practices.

Seems to me this tool sits squarely in that first category, enabling rapid prototyping at a lower cost, while still being flexible enough to allow for a wide range of capabilities. I don't get the feeling at all from the introduction that this is meant to compete with Vue, React, Angular et al. but rather be a complement – the tool to reach for when you have an idea and want to hash it out without being encumbered by process.

For what it's worth, I work like this all the time. I have a collection of simple utility functions that I'll include in an html file – F5 is my build process. It's useless for building anything serious, that's when I reach for more structure. I can definitely see something like Alpine replace my homegrown tools for this.


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


Thanks for clarifying on this. This was not the message I inferred by browsing through the README and the examples.

The wording in the README says that Alpine "offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost" which seemed to indicate that it was targeting a similar audience as those libraries.

The intro also didn't really mention anything about it being suited primarily for applications without needing complex composition of logic or any indication of what the authors feel about how big is too big to be suitable for alpine.


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

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.

Hi. Author ot lit-html here.

While for things like full apps, complex components, or any project leaning heavily on type-checking, I obviously mostly agree with you... I'm very intrigued by projects like this and Intercooler.js. I think there's a lot to like here.

JavaScript is a great place to merge data and DOM because data is so much easier to work with in JS than HTML, but if you're starting from HTML already and just want to incrementally add a bit of interactivity these approaches are really appealing. I think we should strive to make the complexity and learning curves as smooth as possible from static pages to full apps. These do that. lit-html and React do in some ways (you can almost copy and paste HTML into JS and have it work) so long as you're very comfortable in JS to begin with.

I've experimented with plain HTML dialects of lit-html and hope to get back to that so that we can have templates-in-HTML and templates-in-JS share semantics and implementation.


No general purpose framework (or language or process or runtime model) will prevent you from making a project unmaintainable over time if you don't have a design and otherwise keep things organized.

It's inherent in the flexibility that a general-purpose framework provides.

Conversely, if you stay organized, you can maintain long lived complex systems based using frameworks of a variety of styles.

I can assure you there are plenty of old DOM-template-based systems around.


Wow, such an elitist comment.

So you mean endless webpack configurations with tons of javascript libs are more maintainable?

The reverse can be said for SPA-like frontends in which you put forward as the better choice. It's unnecessarily complex and one error and the whole page becomes unresponsive and crashes. How many times haven't we all clicked on a button and because the developer didn't handle some error in a good way the entire page must be reloaded and all state is lost?

You want a good placement on search engines? Well, good luck chuck. Unless you utilize server rendered pages you are out of luck basically. This is also a big hassle. Also server rendered pages are usually slow as fuck compared to a normal multi page app.

I am using lit-html myself and like it, but it's not necessarily better than dom based templating imo. For some things I believe it to be worse. Right now I am on a slow and shaky connection and will be for a while, sites like HN which is a classic multi page app without any javascript loads fast and works great. Pages like youtube and the new reddit (old works great) works like total shite.


Wow, you responded to a pretty thoughtful post with insults, hyperbole and strawmen, and FUD.

> So you mean endless webpack configurations with tons of javascript libs are more maintainable?

I don't think that's what the comment claimed at all. However, I think the answer to the less hyperbolic version of this question is: maybe. It's pretty orthogonal to the discussion though.

> The reverse can be said for SPA-like frontends in which you put forward as the better choice. It's unnecessarily complex and one error and the whole page becomes unresponsive and crashes. How many times haven't we all clicked on a button and because the developer didn't handle some error in a good way the entire page must be reloaded and all state is lost?

I have no idea where you got the idea that this is some defining feature of SPAs, but this is something that can happen with jQuery spaghetti and it's something that almost never happens with React.

> You want a good placement on search engines? Well, good luck chuck. Unless you utilize server rendered pages you are out of luck basically. This is also a big hassle. Also server rendered pages are usually slow as fuck compared to a normal multi page app.

So... I don't know how you're doing this, and admittedly I was away from frontend dev for a few years so I'm sure I missed some pain in the meantime, but I recently started a project with Next.js, and... this is the exact opposite of my experience. SSR is super fast, it only happens once, you get static HTML output and your site is basically as fast as your web server/CDN. All of this without any config.


> So... I don't know how you're doing this, and admittedly I was away from frontend dev for a few years so I'm sure I missed some pain in the meantime, but I recently started a project with Next.js, and... this is the exact opposite of my experience. SSR is super fast, it only happens once, you get static HTML output and your site is basically as fast as your web server/CDN. All of this without any config.

This is only partly true if you use a big framrework like Next or Nuxt but it also means you will heavily buy into whatever these frameworks choose for you. For example, a node backend.

The pages are not faster, especially after adding some complexity like most websites require. The time to render is higher, input lag is commonplace. You're sending the html for that site + all the javascript that needs to be parsed to get that SPA-app that everyone wants.

And as soon as you step outside what the framework requires you too, for example using another backend. Then you're back to a classical SPA-application.

I like SPA-applications that are done well or when they are required, but the complexity to create one is a lot higher because the developers needs to reimplement what the browser originally did for you.


> This is only partly true if you use a big framrework like Next or Nuxt but it also means you will heavily buy into whatever these frameworks choose for you. For example, a node backend.

I mean this in the kindest way: I don't think you fully understand what you're talking about. Next may provide some batteries, but it's hardly a "framework". It does not require you to use any particular part of its functionality. For instance, the site I'm building does not have a backend, node or otherwise, at all. If your server-rendered pages don't need to perform anything asynchronously to render, it just spits out HTML files and you can use whatever you want for a backend.

> The pages are not faster, especially after adding some complexity like most websites require. The time to render is higher, input lag is commonplace. You're sending the html for that site + all the javascript that needs to be parsed to get that SPA-app that everyone wants.

This is simply not an accurate representation of what I am experiencing with Next. It produces static HTML files. They load as fast as any other HTML files. If you do need to dynamically load data on the server, yes you are constrained by the server's performance generating that data, but that is true of any server-rendered dynamic data on any platform.

> And as soon as you step outside what the framework requires you too, for example using another backend. Then you're back to a classical SPA-application.

Okay? Yes, using a tool for otherwise than its intended purpose is definitely more complex than using it for its intended purpose. But like... Next with another backend is basically Create React App with a simple built in router and some compilation optimizations that you don't have to configure.

> I like SPA-applications that are done well or when they are required, but the complexity to create one is a lot higher because the developers needs to reimplement what the browser originally did for you.

You really don't. To the extent SPAs "reimplement" anything, these things are all basically solved problems.

- - -

I just want to add that there are use cases for something like Next that aren't necessarily "single page app". I am using it as a static site generator that lets me express my components as React components, which is renderer-agnostic should I ever want to render to another target, and which has a huge ecosystem I can tap into (for example I am using mdxjs to produce most of this site's content in Markdown with the ability to customize how certainn parts of the MD content is rendered using... React components).

This site is fully static. It's not "slow", it doesn't require a "framework" or a "backend". It is by far the best static site dev experience I've ever had.


I didn't mean to imply that everyone should start using SPAs or people should eschew server-rendered pages.

While search engines have gotten quite better handling javascript, but that was not the point of my comment.

I was mainly outlining my own subpar experience working with libraries having similar approaches in medium-size teams (~30 devs, about 60% of them juniors).

I just hope that people evaluate the potential drawbacks of this approach before jumping into this because it is convenient to get started with.

Angular 1 was also pretty popular in its glory days and as I have learnt the hard way popularity is not a good indicator of either longevity or quality.

I also suggested some alternatives that I have found in my experience to be better suited towards the task of enhancing server-rendered markup.

If one has evaluated related alternatives, weighed pros and cons and settled on alpine, well, power to them.


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.


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!


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/

[1]https://angularjs.org/


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.


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...


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.

How does this compare to Intercooler.js?

https://intercoolerjs.org/


Intercooler is all about getting HTML into your DOM that you get from AJAX requests without actually writing any Javascript. Alpine is more about Interactivity within the current page, without doing a request first. It keeps the state in a data object.

Of course you can do similar things as you would do in Intercooler, but it would be explicit in the Javascript part. See this example they give for prefetching dropdown content from the server

    <div x-data="{ open: false }">
        <button
            @mouseenter.once="
                fetch('/dropdown-partial.html')
                    .then(response => response.text())
                    .then(html => { $refs.dropdown.innerHTML = html })
            "
            @click="open = true"
        >Show Dropdown</button>

        <div x-ref="dropdown" x-show="open" @click.away="open = false">
            Loading Spinner...
        </div>
    </div>

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.


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.


Your general data api and your application api should be separated, since they are different concerns with different requirements, as you are discovering.

Intercooler is better mentally modeled going from a traditional web application -> more interactivity rather than going from a JSON data API SPA -> an intercooler application.


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.


> 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.


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.


I believe making proper sense of FCs and the seemingly arbitrary at first glance rules of hooks requires knowing the underpinnings of how hooks get called.

In class-based components “didMount”, “willReceiveProps”, “willUnmount” et al. would be more or less intuitive to a newcomer with just a general idea of how it works.

That I believe makes FCs fundamentally more complex to learn from scratch.

Personally having some experience I go with FCs if there’s a new complex front-end project that is based on React, but I use class-based components if I need to sprinkle a few on a mostly static website that may have to be maintained by someone else.

(Class-based components in a basic case, which would be the case in question, are also quite straightforward to convert to FCs.)


It's even easier to incorporate standard web components, because using them is as simple as using an HTML tag. If you have separate teams of engineers and designers/content creators, web components are a really nice interface that let's the engineers hide all of the implementation complexity for interactive components.

I wish there was a single accepted standard for deploying native components. Last time I checked there were two competing implementations, JS modules (<script type="module" src="my-component.js">) and HTML imports (<link rel="import" href="my-component.html">, my personal favorite).

HTML Imports are not standard and have been removed from Chrome. <script type="module" src="my-component.js"> is indeed the single accepted standard.

The working draft was last updated in December 2019, unfortunate that browser support is so poor.

Browser support isn't poor, it's just not a thing anymore. Chrome removing HTML Imports in _good_ so that we can move on to an agreed upon replacement that integrates with the JS module system like HTML Modules.

Back then I recall HTML modules being used as a synonym with HTML imports… It was contrasted with JS modules. Interesting.

Anyway, the standard is there and apparently being worked on so I fail to see how it entirely isn’t a thing—hopefully another incarnation will land.

All around it just feels like a solid way to bundle all the aspects of an element together.


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

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

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.

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

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.

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

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.


[flagged]


Username fail ?

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.


> 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.




Applications are open for YC Summer 2020

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: