DEV Community

Cover image for Introducing AlpineJs. The Ideal jQuery Replacement
Konstantinos Zagoris
Konstantinos Zagoris

Posted on • Originally published at wittyprogramming.dev

Introducing AlpineJs. The Ideal jQuery Replacement

Most uncomplicated today web sites, like blogs or landing pages, do not need extensive javascript frameworks with complicated build steps.

Let's take, for example, the Virtual-DOM concept that is so popular today. Do you need this abstraction to use it in a form or add some simple user interactions for most web sites?

JQuery took this role in the websites, and it is one of the reasons that it is still one of the most popular libraries. Unfortunately, jQuery is a child of an old era and does not consider modern concepts such as the reactive state. Furthermore, most jQuery features, such as selectors or simplified AJAX calls, are replaced by modern javascript.

The question to jQuery replacement for most web sites' simple logic tasks can answer the Alpine.js framework. It substitutes the jQuery query-based (imperative) approach with the tailwindcss-inspired declarative approach on the DOM using a familiar Vue-like syntax.

Installation

The installation is simple enough; add a script to the end of your <head> section:

<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
Enter fullscreen mode Exit fullscreen mode

The cost of the library itself is low. The comparison with the other frameworks shows that:
Bundle Cost

Alpine.js Example

Let's introduce ourselves to this framework by using, as an example, a simple login form. The user provides the username and password, and if the supplied password is equal to pass, then a welcome message is displayed tailored to the given username. Otherwise, an error message is displayed.

The whole code is displayed here:

<div x-data="{ username:'', password: '', login : false, error: false }">
    <form x-show="!login" x-on:submit.prevent="error=false;
        if (password === 'pass') 
        login = true; 
        else error = true;" method="post">
        <div>
            <label for="username"><b>Username:</b></label>
            <input x-model="username" type="text" placeholder="Enter Username" name="username" required />
        </div>
        <div>
            <label for="password"><b>Password: </b></label>
            <input x-model="password" type="password" placeholder="Enter Password" name="password" required />
        </div>
        <div>
            <button type="submit">Login</button>
        </div>
        <div>
            <label>
                <input type="checkbox" checked="checked" name="remember" /> Remember
                me
            </label>
        </div>
    </form>
    <div x-show="login" x-text="`welcome ${username}`"></div>
    <div x-show="!login && error" style="color: red;">Login failed!</div>
</div>
Enter fullscreen mode Exit fullscreen mode

Component Initialization

Take note of the following code:

<div x-data="{ username:'', password: '', login : false, error: false }">
Enter fullscreen mode Exit fullscreen mode

In the above line, we initialize a component with the corresponding data object. Specifically, we initialize an empty username and password string and set the login and error as false.

The x-data attribute plays a similar role to a Vue's component data property. Accordingly, these variables are reactive, as you will expect from the Vue.js experience.

Take note that if you seek something like the mounted() in VueJS or the ngOnInit() in Angular hooks, the x-init attribute is more appropriate.

Binding

The next step involves the approaches to the variable binding. The following code binds the variable username to the input element's value using the x-model attribute.

<input x-model="username" type="text" placeholder="Enter Username" name="username" required />
Enter fullscreen mode Exit fullscreen mode

The x-model attribute, as you probably guessed, is similar to Vue.js's v-model attribute and implements a two-way binding between the variable and the value of the element.

For one way binding, the x-bind attribute is used and similar to Vue.js there is the shorter syntax of :attr. The following two example are equivalent:

<a x-bind:href="homeUrl">Home</a>
<a :href="homeUrl">Home</a>
Enter fullscreen mode Exit fullscreen mode

Two other one-way bindings similar to the x-bind attribute are the x-text and the x-html attributes. The first one will update the element's innerText and the second the element's innerHTML values. At our login form example, we used the x-text attribute to display a welcome login message based on user's username:

<div x-show="login" x-text="`welcome ${username}`"></div>
Enter fullscreen mode Exit fullscreen mode

Toggle Display

The x-show attribute in Alpine.js toggles the display:none element's style depending on the expression's outcome. The above example will show the welcome message when the login is set to be true.

Another similar attribute is the x-if, which completely removes the element from the DOM but has two significant constraints. Because the Alpine uses the real DOM and not a virtual, the first constraint is that the x-if attribute must be applied on a <template></template> tag. Consequently, the second constraint is that the <template></template> must have a single element root. The equivalent of the above x-show example using the x-if attribute is:

<template x-if="login">
    <div x-text="`welcome ${username}`"></div>
</template>
Enter fullscreen mode Exit fullscreen mode

Loops

The same limitations are applied for the x-for attribute, which creates new DOM nodes based on an array similar
to the Vue's v-for.:

<template x-for="item in items" :key="item">
    <div x-text="item"></div>
</template>
Enter fullscreen mode Exit fullscreen mode

For inner loops the same considerations is applied:

<template x-for="item in items">
    <div>
        <template x-for="subItem in item.subItems">
            <div x-text="subItem"></div>
        </template>
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

The limitation which the template tag enforces must be under constant consideration when you want to use loops or the x-if attribute.

Events

For listening and responding to events, the x-on:event or the alternative syntax @:event is used. Similar to Vue, the x-on attaches an event listener to the corresponding element's event. When that event is emitted, the specified expression is executed. In our example, when the form is submitted, we check if the password is correct and then setting the corresponding variable.

 <form x-show="!login" x-on:submit.prevent="error=false;
         if (password === 'pass') 
            login = true; 
         else error = true;" method="post">
Enter fullscreen mode Exit fullscreen mode

The final result looks like this:

Conclusion

The Alpine.js advantages present during simple DOM manipulation based on user interactions; therefore, it is most suitable for:

  • showing, hiding, or removing DOM nodes under certain conditions
  • two-way or one-way binding of attributes
  • watching and responding to user/UI events

In the next articles in the Alpine.js series, I will write some more advantage tools like:

  • reusable functions for minimizing javascript code in DOM and allowing code reuse
  • the spruce library as a global state for simplifying the inter-component communication
  • several magic helpers will help facilitate some common patterns like ajax interactions or parent component access.

The above tools help us to use Alpine.js for more advanced implementations.

In the end, if you seek a suitable and easy replacement for jQuery, I think you will find Alpine.js most suitable.

Top comments (0)