Getting started with Alpine.js
Tags: javascript, webdev, tutorial
Published: 2020-05-12 15:26:18

---
title: Getting started with Alpine.js
published: true
date: 2020-04-16 13:00:03 UTC
tags: javascript, webdev, tutorial
canonical_url: https://blog.logrocket.com/getting-started-with-alpine-js/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/6cp0xndzaysrnq49nqhi.png
---
**Written by [Godwin Ekuma](https://blog.logrocket.com/author/godwinekuma/)**✏️

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

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

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

```jsx
<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`.

```jsx
npm i alpinejs
```

### Basic component

```jsx
<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:

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

```jsx
<div x-data="[JSON data object]">...</div>
```

**Example**:

```jsx
<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:**

```jsx
<div x-data="..." x-init="[expression]"></div>
```

**Example**:

```jsx
//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:**

```jsx
<div x-show="[expression]"></div>
```

**Example:**

```jsx
<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:**

```jsx
<input x-bind:[attribute]="[expression]">
```

Alpinejs provides `x-bind` as a mechanism for binding value, boolean, and class attributes.

**Value attribute binding**:

```jsx
<img x-bind:src="imgSrc">
```

This sets the value of an attribute to the result of the expression.

**Class attribute binding:**

```jsx
<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:**

```jsx
<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:**

```jsx
<input x-on:[event]="[expression]">
```

**Example:**

```jsx
<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:**

```jsx
<template x-if="[expression]"><div>Some Element</div></template>
```

**Example:**

```jsx
<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:**

```jsx
<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:**

```jsx
<input type="search" x-model="[data item]">
```

**Example:**

```jsx
<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:**

```jsx
<span x-text="[expression]"></span>
```

**Example:**

```jsx
<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:**

```jsx
<p x-html="[expression]"></p>
```

**Example:**

```jsx
<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.

```jsx
<!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](https://pixabay.com/) 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`.

{% codepen https://codepen.io/godwinekuma/pen/QWboBOO %}

## 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](https://github.com/alpinejs/alpine), where you can keep up with developments and news.

* * * 
## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) 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](https://logrocket.com/signup/).
* * *

The post [Getting started with Alpine.js](https://blog.logrocket.com/getting-started-with-alpine-js/) appeared first on [LogRocket Blog](https://blog.logrocket.com).