tutos

Bulma grid with an alpine JS loop

Sunday 31st January, 2021 —

What is alpine JS?

Alpine.js is a simplistic and lightweight javascript framework that offers the reactive and declarative nature of big frameworks like Vue or React at a much lower cost. Like its author says: "You get to keep your DOM, and sprinkle in behavior as you see fit". Alpine.js documentation fits on its GitHub readme file, and that makes it pretty easy to learn. If you don't know alpine JS, then you should definitely check out the GitHub repository.

What we'll be building

We'll be shortly building a quick card grid using Bulma and Alpine.js. We will be using one of Alpine's directives named x-for, which is pretty similar to Vue's v-for.

Markup and styles

Let's begin with the html markup we are going to need for our grid.

<script setup lang="ts">
type TotoType = { foo: string }
const toto: TotoType = { foo: "bar" }
</script>

<template>
  <div class="section">
    <div class="container">

      <div class="has-text-centered">
        <h1 class="title">Bulma + Alpine.js Loop</h1>
      </div>

      <div class="grid py-6" x-data="{}">
        <div class="columns is-multiline">

        </div>
      </div>
    </div>
  </div>
  </div>
</template>

First we're setting up the basic UI for the demo. Then we're creating a grid wrapper and we tell alpine to register it as a component by using the x-data attribute. Note that we are passing an empty object since we won't be using methods in this example. Let's add some basic styles for everything to look decent:

$font: 'Roboto', sans-serif;
$primary: #4e1b96;
$text: #97a1c9;

h1 {
  font-family: $font;
}

.grid {
  max-width: 940px;
  margin: 0 auto;
}

.box {
  border: 1px solid #ededed;

  figure {
    margin: 0 auto;
  }

  h3 {
    font-family: $font;
  }

  p {
    font-family: $font;
    font-size: 0.9rem;
    color: $text;
  }

  .button {
    font-family: $font;
    min-width: 110px;
    border-radius: 0.75rem;
    transition: all 0.3s;

    &:hover {
      background: $primary;
      border-color: $primary;
      color: #fff;
    }
  }
}

We are using a Bulma .box element to create a card that provides an image, some text and an action.

Prepping data

In order to use the x-for directive, we need to provide some data, so we can loop through it. Let's declare an array of users:

const users = [
  {
    photo:
      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ7y3Z1KmRcTWjevKLfro5sVhQAGhdjt7ifDw&usqp=CAU',
    name: 'Alex B.',
    position: 'Software Engineer',
  },
  {
    photo:
      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSQ_u-gnmeOdsfZMOpBTzqqcnBZwo8dWu38-Q&usqp=CAU',
    name: 'Claudia C.',
    position: 'Software Engineer',
  },
  {
    photo:
      'https://media.nngroup.com/media/people/photos/DSC02880-5.jpg.600x600_q75_autocrop_crop-smart_upscale.jpg',
    name: 'Miranda B.',
    position: 'Sales Manager',
  },
  {
    photo:
      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTlQBG3l--K5nc9j9Q2rOI3F2aLBlGlkMUZAg&usqp=CAU',
    name: 'Mike D.',
    position: 'CTO',
  },
  {
    photo:
      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRLe5PABjXc17cjIMOibECLM7ppDwMmiDg6Dw&usqp=CAU',
    name: 'John V.',
    position: 'Marketing Associate',
  },
  {
    photo:
      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRZ2deIjGHBybec2nxndF_VstcGL_qLpomozw&usqp=CAU',
    name: 'Adam F.',
    position: 'Finance Consultant',
  },
]

Using x-for

In order to loop our user list with alpine, we are going to provide a UI element for the data we want to render. We will be wrapping that element inside a template HTML tag.

<template x-for="(user, index) in users" :key="index">
  <div class="column is-4">
    <div class="box has-text-centered">
      <figure class="image is-64x64">
        <img class="is-rounded" :src="user.photo" />
      </figure>
      <div class="py-4">
        <h3 x-text="user.name">Alex B.</h3>
        <p x-text="user.position">Software Engineer</p>
      </div>
      <a class="button">Hire Now</a>
    </div>
  </div>
</template>

x-for="(user, index) in users" is very similar to what you would see with Vue. It maps the array and lets you access every property to populate your template. The index value is also available within the loop if you want to use it. We are also using the x-text alpine directive, which imitates the behavior of the native javascript element.innerHTML method. Copy the template above, and paste it inside the grid columns we previously created. And that's it. you don't need to do anything else. Alpine will take care of everything, generating n elements and assigning the proper values. Look at the pen below for the full example.

See the Pen Bulma + Alpine.js Loop by Driss Chelouati (@cssninjaStudio) on CodePen.

Epilogue

Using Alpine.js in that use case was amazingly simple and fast. You get to create UI loops with just a few lines of code and that's exactly why it makes it so powerful. If you still not sure about Alpine.js, then you should definitely give it a try!

Back to Blog

Continue reading

Server Cache Invalidation in Nuxt and Nitro

Top 10 Vue Components Libraries

How to build a filterable list with Nuxt and Tailwind