loading...
Cover image for The rise of alpine JS?

The rise of alpine JS?

sroehrl profile image neoan ・3 min read

code
video

I keep hearing about alpine, but what is it?

Yet another javascript-framework? Yes and no: the project describes itself as "A rugged, minimal framework for composing JavaScript behavior in your markup."

Ok? What does that mean? It means you will write logic directly in your html - at least for the most part. It's not as powerful, not as versatile and not as complex as other frameworks. But it's light, fast and super easy to use & implement.

Let's give it a spin

After reading the basics (and there isn't much more after that), it seems like there is no advantage to installing alpine locally. So feel free to simply include the cdn and directly give it a spin:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Alpine test</title>
    <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.3.5/dist/alpine.min.js" defer></script>
</head>
<body>
<div x-data="{show:false}"> <!-- declare model 'show' -->
    <p x-show="show">Only show if "show" is true</p> <!-- display condition -->
    <button @click="show =! show">toggle show</button> <!-- simple click event listener/setter -->
</div>
</body>
</html>

The first thing we notice is the direct declaration of data in the DOM. Even with aditional javascript, we need this for initialization. Of course we could write some external JS, ask a server for some data and then provide it to x-data, but in order to play with the "pure markup" approach, I decided to combine it with the neoan3 template engine and directly write server side data into the DOM.

neoan3 route (here component/home):

<?php

/* Generated by neoan3-cli */

namespace Neoan3\Components;

use Neoan3\Core\Unicore;

/**
 * Class Home
 * @package Neoan3\Components
 */

class Home extends Unicore{
    /**
     * Route: home
     */
    function init(): void
    {
        $this
            ->uni('Alpine')
            ->hook('main', 'home', $this->tabsAndContent())
            ->output();
    }
    function tabsAndContent()
    {
        return [
            'tabs' => [
                ['title'=>'first tab', 'content'=> 'content one'],
                ['title'=>'second tab', 'content'=> 'content two'],
                ['title'=>'third tab', 'content'=> '<img src="'.base.'asset/neoan-favicon.png">']
            ]
        ];
    }
}

neoan3 home-component view

<div class="mt-2 px-2" x-data="{tab: '{{tabs.0.title}}'}" xmlns:x-on="http://www.w3.org/1999/xhtml">
    <ul class="flex border-b">
        <li class="-mb-px mr-1" n-for="tabs as tab">
            <a x-on:click="tab='{{tab.title}}'" href="#" class="tab-a" :class="{'active':tab=== '{{tab.title}}'}">
                {{tab.title}}
            </a>
        </li>
    </ul>
    <div class="mt-3 w-2/3 mx-auto border rounded-b">
        <div n-for="tabs as tab" class="px-4 py-2" x-show="tab === '{{tab.title}}'">
            {{tab.content}}
        </div>
    </div>
    <div class="mt-4 w-2/3 mx-auto">
        <select x-model="tab" class="shadow w-full appearance-none px-2 bg-white py-2">
            <option n-for="tabs as tab" value="{{tab.title}}">go to {{tab.title}}</option>
        </select>
    </div>
</div>

Let's walk over this:

I generate some mock data in a PHP function and pass it to the template. We now have the tabs-variable available in the view.
In the view, we define the initial state of alpine's x-data key "tab" with the first tab title. Once rendered, our output of the first statement would look as simple as

x-data="{tab: 'first tab'}"

We then use the template engine to iterate over our tabs server side (n-for). Feel free to question that: we could have also passed tabs as an object and iterate with alpine's x-for on the client. However, I decided to use it as how I think it's intended: as a way to easily create dynamic behavior on otherwise static pages. In other words: as a way out of the staleness without creating a heavy js instance.

Conclusion

Alpine is surprisingly easy. I required basically no time to understand and use it. Whether you use handlebars, blade, twig or neoan3: it feels like the combination with a backend template engine is ideal.
I like working with Vue and React, but especially React is an untamable monster if you are not building an SPA. You might not notice it, but the acrobatics technologies go through to make something like next work is almost insane compared to what we want to achieve. Alpine is not a powerful JS solution - it's the tool that does its job for the 80% of your projects where you don't need to reinvent the wheel. And at that it's making a great first impression.

Discussion

pic
Editor guide