Using AlpineJS to make things pretty
Published: 2021-04-13 12:15:59

---
title: Using AlpineJS to make things pretty
published: true
date: 2021-04-12 09:00:00 UTC
tags: 
canonical_url: https://www.solarwinter.net/using-alpinejs-to-make-things-pretty/
cover_image: https://www.solarwinter.net/content/images/2021/04/alpine-pretty-1.png
---

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.

![Using AlpineJS to make things pretty](https://www.solarwinter.net/content/images/2021/04/alpine-animation-1.gif)<figcaption>Example animation of Alpine</figcaption>

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

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

![Using AlpineJS to make things pretty](https://www.solarwinter.net/content/images/2021/04/source.gif)<figcaption>Lightbulb</figcaption>

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.

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

```html
<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](https://alpinetoolbox.com/), and we see that in fact there are already multiple modal examples that we can derive from.

[This excellent post](https://williamrodriguez.com/articles/alpinejs-tailwindcss-responsive-modal-tutorial) makes a good starting point. We replace the body of it with the tweaked form above and we get the following effect:

![Using AlpineJS to make things pretty](https://www.solarwinter.net/content/images/2021/04/alpine-dialog-anim.gif)

I took the chance to improve the look of the buttons slightly, since we’ve pulled in [Tailwind](https://tailwindcss.com/) from the example. Much better than having to click through to a separate page!