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>
The cost of the library itself is low. The comparison with the other frameworks shows that:
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>
Component Initialization
Take note of the following code:
<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 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 />
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>
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>
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>
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>
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>
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">
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)