3 min read

How to make your Web Pages look Prettier with Alpine.js

How to make your Web Pages look Prettier with Alpine.js

I had a revelation the other day.

In the beginning…

I had this idea that to make your UI pretty and reactive you needed to be using Vue, Svelte, or some other web framework. Otherwise the page just sat there until you clicked a button, then reloaded. Silly, I now know.

Then I discovered AlpineJS, and realised I was completely wrong.

Example animation of Alpine
Example animation of Alpine

That animation above is the result of the markup below. Literally, that’s it.

<html>
  <head>
    <title>Alpine demo page</title>
    <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.8.2/dist/alpine.min.js"></script>
  </head>
  <body>
    <div x-data="{ show: false }">
      <label for="name">Please enter your name: </label>
      <input type="text" name="name" x-ref="name">
      <button
        @click="show = !show"
        x-text="show ? 'Stop saying hello' : 'Say hello'"
      ></button>
      <div x-show="show">
        <p x-text="'Hello ' + $refs.name.value"></p>
      </div>
    </div>
  </body>
</html>

The magic happens with the x- tags:

  • x-data declares a variable - you can only use the variable within the scope of that block
  • x-show decides visibility
  • x-text controls the innerText of the element it’s on.
  • @click can be used as a shorthand for listening to events. It’s a shortcut for x-on.
  • x-ref adds a reference to the element, making it accessible later through $refs.

Put those together and you can do some amazing things.

Using it

On most of my projects I’ve had a separate page for deleting items. The flow wasn’t as smooth as I’d have liked, but it worked.

Then I had a Gru moment.

Lightbulb
Lightbulb

Why a whole separate page? All I actually need is a POST request to the right URL. I can do that with a form. We already know Alpine can show and hide the form.

Since there’s no data that has to be conveyed the form only actually has to surround the submit buttons.

<form action="/people/<%= person.id %>/delete" method="POST">
  <div>
    <button>Cancel</button>
    <button type="submit" >Delete</button>
  </div>
</form>

If we’re going to use Alpine then we need to tweak the form ever so slightly, replacing the cancel button.

<button @click.prevent="showDelete = false">Cancel</button>

The .prevent stops the click event from being propagated up - if that wasn’t there then the button would register the click, and as well as hiding the delete dialogue it would actually submit the form and delete the item.

Let’s go along to the (really useful) Alpine toolbox, and we see that in fact there are already multiple modal examples that we can derive from.

This excellent post makes a good starting point. We replace the body of it with the tweaked form above and we get the following effect:

I took the chance to improve the look of the buttons slightly, since we’ve pulled in Tailwind from the example. Much better than having to click through to a separate page!