AlpineJS – a lightweight alternative to Vue

Pitched as Tailwind for JS, this new framework from Caleb Porzio is full of promise.

Published December 21st 2019

It's not often that after playing around with new a tool, I immediately get the urge to sit down and blog about it. But that's precisely what happened when I managed to get some proper hands on time with Caleb Porzio's latest project – AlpineJS.

Pitched as 'Tailwind for JS', it's intended to bring you the reactivity and state management of larger tools like Vue and React, but without the overhead. How does it do that? Well, it does it by focusing on just the behaviour most websites use, instead of the tools needed to build single page applications.

A basic example

If I need to build a dropdown menu, my go-to tool today is Vue. Building these components in Vue is trivial, at least compared to doing it in vanilla JavaScript or jQuery.

A few extra directives in the HTML, and a couple of lines of code in a JavaScript file is all that's needed to create what would have previously taken 30+ lines of JavaScript.

Previously known as Project X, AlpineJS takes that concept even further. If you use the CDN, the framework will even initialise itself. Four directives are all that is needed to create a functioning dropdown menu, or modal.

<div x-data="{ open: false }">
    <button x-on:click="open = true">Open Dropdown</button>

    <ul x-show="open" x-on:click.away="open = false">
        Dropdown Body
    </ul>
</div>

Breaking it down

The x-data directive tells AlpineJS that you want to create a new component, with its own scope. It's like the data property you may be used to in Vue.

There are two ways you can use this directive. You can either pass in a JSON data object, like in the example above, or you can give it a name, which is associated to a function. The latter is particularly useful when you want to extract data and behaviour for use elsewhere.

For example, you could achieve the same, but in a reusable way, by switching out the data object value { open: false } with the function dropdown().

<div x-data="dropdown()">
    <button x-on:click="open = true">Open Dropdown</button>

    <ul x-show="open" x-on:click.away="open = false">
        Dropdown Body
    </ul>
</div>

...

<script>
    function dropdown() {
        return {
            show: false
        }
    }
</script>

You can further extract the rest of the logic in a similar way, resulting in:

<div x-data="dropdown()">
    <button x-on:click="open()">Open Dropdown</button>

    <ul x-show="isOpen()" x-on:click.away="close()">
        Dropdown Body
    </ul>
</div>

...

<script>
    function dropdown() {
        return {
            show: false,
            open() { this.show = true },
            close() { this.show = false },
            isOpen() { return this.show === true },
        }
    }
</script>

For most basic use cases though, it'll be perfectly fine to use the the data object approach.

The x-on and x-show properties also take inspiration from Vue's naming conventions. So if you're used to Vue, it should be pretty clear how these work.

The only thing that's slightly different are the inline modifiers. .away for example, will only trigger the event handler is triggered on a source other than itself, or its children.

A good example of this is closing a dropdown menu unless the user is clicking in the dropdown or one of the child elements of the dropdown. There are also plenty of other methods available, so it's worth checking out AlpineJS's GitHub repo.

Over the coming weeks, I'll be writing up some tutorials tackling some common patterns used in modern websites, but if you want to find out more right now, you can check out the project's readme.