Godwin Ekuma I learn so that I can solve problems

Getting started with Alpine.js

7 min read 2096

Getting Started With Alpine.js

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.

We made a custom demo for .
No really. Click here to check it out.

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:

  1. x-data
  2. x-init
  3. x-show
  4. x-bind
  5. x-on
  6. x-if
  7. x-for
  8. x-model
  9. x-text
  10. 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.

See the Pen
Alpinejs_Tutorial
by Godwin Ekuma (@godwinekuma)
on CodePen.

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.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution 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.

.
Godwin Ekuma I learn so that I can solve problems

One Reply to “Getting started with Alpine.js”

  1. Nested x-for are only possible with a later version of AlpineJS than is used in this example.

Leave a Reply