Introducing AlpineJs. The Ideal jQuery Replacement
Tags: javascript, html, webdev, beginners
Published: 2021-02-08 07:06:34

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](https://jquery.com/) 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](https://github.com/alpinejs) 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:

```html
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
```

The cost of the library itself is low. The comparison with the other frameworks shows that:
![Bundle Cost](https://dev-to-uploads.s3.amazonaws.com/i/f4zf2ht2d0aim8psh1ap.png)

# 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:

```html
<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>
```

# Component Initialization

Take note of the following code:

```html
<div x-data="{ username:'', password: '', login : false, error: false }">
```

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](https://github.com/alpinejs/alpine#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](https://github.com/alpinejs/alpine#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.

```html
<input x-model="username" type="text" placeholder="Enter Username" name="username" required />
```

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](https://github.com/alpinejs/alpine#x-bind) attribute is used and similar to Vue.js there is the shorter syntax of `:attr`. The  following two example are equivalent: 

```html
<a x-bind:href="homeUrl">Home</a>
<a :href="homeUrl">Home</a>
```

Two other one-way bindings similar to the `x-bind` attribute are the [x-text](https://github.com/alpinejs/alpine#x-text) and the [x-html](https://github.com/alpinejs/alpine#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:

```html
<div x-show="login" x-text="`welcome ${username}`"></div>
```

# Toggle Display

The [x-show](https://github.com/alpinejs/alpine#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](https://github.com/alpinejs/alpine#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:

```html
<template x-if="login">
    <div x-text="`welcome ${username}`"></div>
</template>
```

# Loops

The same limitations are applied for the [x-for](https://github.com/alpinejs/alpine#x-for) attribute, which creates new DOM nodes based on an array similar 
to the Vue's `v-for.`:

```html
<template x-for="item in items" :key="item">
    <div x-text="item"></div>
</template>
```

For inner loops the same considerations is applied:

```html
<template x-for="item in items">
    <div>
        <template x-for="subItem in item.subItems">
            <div x-text="subItem"></div>
        </template>
    </div>
</template>
```

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](https://github.com/alpinejs/alpine#x-on) 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. 

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

The final result looks like this:

{% codepen https://codepen.io/wittyprogramming/pen/OJXGNGQ %}

# 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](https://github.com/ryangjchandler/spruce) library as a global state for simplifying the inter-component communication
- several [magic helpers](https://github.com/alpine-collective/alpine-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.