Written by Godwin Ekuma✏️
Alpine.js is a rugged, minimal frontend development framework for adding JavaScript behavior to HTML markups. It enables you to harness the reactive and declarative nature of popular frontend libraries and frameworks such as Angular, React, and Vue at a much lower cost. There is no build step and the library file size is about 4KB gzipped.
Alpine is not meant to replace frameworks such as Vue and React; if you have a highly interactive single-page app, it’s best to stick to Angular, Vue, or React. It’s best used when your project requires only minimal JavaScript — such as when you only need one or two components, like dropdowns, sidebars, tabs, and image selection. The framework is great for serverside-rendered apps, such as Laravel and Rails, which require you to toggle some JavaScript components. And since it doesn’t have a virtual DOM, it’s easier to set up and has no build steps.
Essentially, Alpine.js is like Tailwind for JavaScript. The DOM and behavior are not separated; you get to keep your DOM and sprinkle in behavior as you see fit. You can easily write declarative code as opposed to procedural code. Finally, Alpine.js has a very small footprint in your application.
Now let’s move on to installation steps and get our hands dirty with Alpine.js.
Installation and basic use
Installing Alpine.js is easy. You can use either npm or a CDN and add the following to the head section of your HTML.
CDN installation
Insert the code below to the end of the <head>
section of your HTML file.
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.js" defer></script>
NPM installation
Include the following in your script using import alpinejs
.
npm i alpinejs
Basic component
<html>
<head>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.9.8/dist/alpine.js" defer></script>
</head>
<body>
<div x-data="{ isOpen: true }">
<button x-on:click=" isOpen = !isOpen">Toggle</button>
<h1 x-show="isOpen">Alpinjs</h1>
</div>
</body>
</html>
The first step to using Alpine is to define a state. The state goes wherever it is needed and has the same scope as the HTML selector you put in.
In the code above, we defined a scope using the x-data
directive by passing in an object as the value of the state. The x-on
directive listens for events. For the button
element, we’re listening to the click event, which changes the value of isOpen
to true
or false
. The x-show
directive shows or hides an element from the DOM depending on the value of the state object’s isOpen
property.
Common Alpine.js directives
At the core of the Alpine.js framework are directives, which change the DOM layout by adding and removing DOM elements and alter the behavior and appearance of elements in the DOM.
There are about 13 directives in Alpine, but for the purpose of this tutorial, we’ll focus on 10 of the most commonly used directives:
x-data
x-init
x-show
x-bind
x-on
x-if
x-for
x-model
x-text
x-html
1. x-data
Syntax:
<div x-data="[JSON data object]">...</div>
Example:
<div x-data="{ foo: 'bar' }">...</div>
x-data
initializes a new component scope (state) with an object in an HTML element. All child HTML elements have access to the data object that exists in its parent element.
2. x-init
Syntax:
<div x-data="..." x-init="[expression]"></div>
Example:
//1: runs on DOM initialization.
<div x-data="{ title: 'foo' }" x-init="title = 'bar'"></div>
//2 : runs post DOM initialization.
<div x-data="images()"
x-init="fetch('https://pixabay.com/api/?key=15819227-ef2d84d1681b9442aaa9755b8&q=yellow+flowers&image_type=photo')
.then(response => response.json())
.then(response => { images = response.hits })"></div>
x-init
is used to run an expression when a component initializes. You can also use x-init
to run code after a component initializes by passing a callback function. x-init
is used in combination with x-data
to set the initial value of the component state.
3. x-show
Structure:
<div x-show="[expression]"></div>
Example:
<div x-show="isOpen"></div>
x-show
changes the CSS display property of the element depending on whether the expression evaluates to true
or false
. If the expression evaluates to false
, the element’s display property is toggled to none
. If it resolves to true
, the display property is toggled to its default.
4. x-bind
Syntax:
<input x-bind:[attribute]="[expression]">
Alpinejs provides x-bind
as a mechanism for binding value, boolean, and class attributes.
Value attribute binding:
<img x-bind:src="imgSrc">
This sets the value of an attribute to the result of the expression.
Class attribute binding:
<div x-bind:class="{ 'hidden': isClosed }"></div>
For class binding, an object expression is passed. The object keys are class names and the values are boolean expressions. If the boolean expression evaluates to true
, the class name will be applied to that element.
Boolean attribute binding:
<input type="text" x-bind:hidden="true">
Boolean binding works the same way as attribute binding, but the expression passed has to evaluate to true
or false
.
5. x-on
Syntax:
<input x-on:[event]="[expression]">
Example:
<input x-on:input="foo = 'bar'">
x-on
adds an event listener to the element on which it’s declared. When the element emits that event (e.g., a click or input event), the expression set as the value of x-data
will be executed.
6. x-if
Syntax:
<template x-if="[expression]"><div>Some Element</div></template>
Example:
<template x-if="true"><div>...</div></template>
While x-show
can be used to toggle the display property of an element, the element is typically not removed from the DOM. The x-if
directive doesn’t hide elements with CSS; it adds and removes them physically from the DOM.
The value of x-if
is a boolean expression that can evaluate to true
or false
. If the expression evaluates to false
, x-if
removes its host element from the DOM. x-if
only works within the template
element and must have a single element root inside the template
tag.
7. x-for
Example:
<template x-for="item in items" :key="item">
<div x-text="item"></div>
</template>
x-for
helps when you want to create new DOM nodes for each item in a collection. Just like the x-if
directive, the x-for
directive needs to exist on a template
tag, not a regular DOM element.
8. x-model
Syntax:
<input type="search" x-model="[data item]">
Example:
<input type="search" x-model="search">
x-model
adds a two-way data binding capability to an element and synchronizes the value of an input element and the component data. It is smart enough to detect changes on text inputs, checkboxes, radio buttons, textareas, selects, and multiple selects and bind their value to the component data.
9. x-text
Syntax:
<span x-text="[expression]"></span>
Example:
<span x-text="title"></span>
While x-bind
is for attribute binding, x-text
is used to set the value of an element’s innerText
.
10. x-html
Syntax:
<p x-html="[expression]"></p>
Example:
<p x-html="text"></p>
x-html
works similarly to x-text
, but instead of setting the innerText
, it sets the value of the innerHTML
of an element.
Building an image gallery with Alpinejs
To demonstrate how the directives can be used together, let’s build a simple image gallery.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<!-- Bootstrap CSS -->
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous"
/>
<!-- Custom CSS -->
<link rel="stylesheet" href="css/custom.css" />
<!-- Fonts -->
<link
href="https://fonts.googleapis.com/css?family=Lora:400,700|Nunito:400,700"
rel="stylesheet"
/>
<script
src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v1.9.8/dist/alpine.js"
defer
></script>
<script
defer
src="https://use.fontawesome.com/releases/v5.0.7/js/all.js"
></script>
<link
href="images/favicon_32.ico"
rel="shortcut icon"
type="image/x-icon"
/>
<link href="images/favicon_256.ico" rel="apple-touch-icon" />
</head>
<body
x-data="images()"
x-init="fetch('https://pixabay.com/api/?key=15819227-ef2d84d1681b9442aaa9755b8&q=yellow+flowers&image_type=photo')
.then(response => response.json())
.then(response => { images = response.hits })"
>
<!-- Header section -->
<header class="navigation">
<div class="container navigation-content">
<nav class="navbar navbar-expand-lg navbar-light">
<a class="navbar-brand" href="index.html"
><img
src="https://godwinekuma.github.io/we-connect/images/logo-white.svg"
alt="weconnect logo"
height="50"
class="navbar-brand-image"
/>
PictureGram</a
>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
</nav>
</div>
</header>
<!-- Header section /-->
<!-- Hero Section -->
<div>
<section class="hero">
<div class="container">
<div class="d-flex flex-column align-items-center">
<h1 class="display-4" style="text-align:center">
Search for images.
</h1>
<h2 class="" style="text-align:center">
Pixel perfect images can be found here.
</h2>
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="search images"
x-model="q"
aria-label="Text input with segmented dropdown button"
/>
<select class="custom-select" x-model="image_type">
<option selected>choose image type</option>
<option value="all">All</option>
<option value="photo">Photo</option>
<option value="illustration">Illustration</option>
<option value="vector">Vector</option>
</select>
<div class="input-group-append">
<button
class="btn btn-primary"
type="button"
x-on:click="getImages()"
>
Search
</button>
</div>
</div>
</div>
</div>
</section>
<section id="photos" class="my-5">
<template x-for="image in images" :key="image.id">
<img x-bind:src="image.webformatURL" alt="image.tags[0]" />
</template>
</section>
</div>
<script>
function images() {
return {
images: [],
q: "",
image_type: "",
getImages: async function() {
console.log("params", this.q, this.image_type);
const response = await fetch(
`https://pixabay.com/api/?key=15819227-ef2d84d1681b9442aaa9755b8&q=${
this.q
}&image_type=${this.image_type}`
);
const data = await response.json();
this.images = data.hits;
}
};
}
</script>
</body>
</html>
Our gallery app gets a list of images from Pixabay and displays them. The application state is set on the body
tag by the x-data
directive using a function called images
. The function returns an object that contains image
, q
, image-type
, and getImages
. The initial value of an image is set using the x-init
directive. The x-init
fetches a list of images from Pixabay and sets it as the value of images
field.
q
captures the value of the <input>
and is set using the x-model
directive. image_type
, on the other hand, captures the value of the <select></select>
and is also set using the x-model
directive. We attached a click event listener to the <button>
. When the button is clicked, the getImages()
method in the state is called. The getImages()
method fetches new images based on the value of q
and image_type
.
Conclusion
In this tutorial, we covered how to use Alpine.js and built a sample image gallery component with the framework. Though it might not totally replace other frameworks, it can be used in combination with React or Vue to quickly prototype components without writing much JavaScript.
Be sure to check out Alpine.js on GitHub, where you can keep up with developments and news.
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
Try it for free.
The post Getting started with Alpine.js appeared first on LogRocket Blog.
Top comments (1)
Yet just another JS framework....