Auto Animate
November 10, 2023AutoAnimate is a fantastic little javascript utility I just stumbled across on Twitter. To quote the AutoAnimate website, "AutoAnimate adds automatic animations to your JavaScript applications with a single line of code.". That's it, super easy to install and super easy to use.
I'm a big fan of simple little micro animations and embellishments to spice up websites so I decided to tinker with it using AlpineJs (another favourite of mine). After seeing Ian's tweet I knew this was something I needed to checkout.
Before
I threw together a simple snack generator that randomly grabs a snack and displays it in a grid. Nothing very exciting and as you can see in the video below, pretty blah when items are added/remove and shuffled. The important thing is that it add/removes DOM elements in a parent which is all AutoAnimate needs to see to make some magic happen. Here's the AlpineJs data class I used
Alpine.data("snacks", () => {
return {
emojis: [
{name: 'Hamburger', emoji: '🍔'},
{name: 'Pizza', emoji: '🍕'},
{name: 'Taco', emoji: '🌮'},
{name: 'Salad', emoji: '🥗'},
{name: 'Sandwich', emoji: '🥪'},
{name: 'Soup', emoji: '🍲'},
{name: 'Sushi', emoji: '🍣'},
{name: 'Spaghetti', emoji: '🍝'},
{name: 'Chicken', emoji: '🍗'}
],
items: [],
id: 0,
shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
},
add(){
this.id=this.id+1;
let idx = Math.floor(Math.random(1)*this.emojis.length);
this.items.push({name: this.emojis[idx].name, emoji: this.emojis[idx].emoji, id: this.id});
this.emojis.splice(idx,1);
},
remove(id){
let idx = this.items.findIndex(element => element.id == id);
this.items.splice(idx,1);
}
}
});
And here's the HTML, notice the `x-animate` attribute on the main DOM element and the DIV that contains all the snacks.
<div class="w-1/2 p-5 border border-black rounded-md " x-data="snacks()" x-animate>
<div class="flex flex-row justify-between items-center">
<button class="font-bold border-black border-2 px-4 py-2 rounded-md hover:bg-green-300 transition duration-200 "
@click="add()">Add A Snack</button>
<button class="font-bold border-black border-2 px-4 py-2 rounded-md hover:bg-green-300 transition duration-200"
@click="shuffle(items);">Shuffle</button>
</div>
<template x-if="items.length > 0">
<div class="grid grid-cols-2 gap-4 mt-5 transition duration-500" x-animate>
<template x-for="item in items" :key="item.id">
<div class="relative group flex justify-between">
<div class="flex items-center gap-5">
<div
class="w-20 h-20 relative rounded-full flex items-center justify-center bg-green-200 border border-green-400">
<span class="text-4xl" x-text="item.emoji"></span>
<button
class=" text-red-500 opacity-0 group-hover:opacity-100 transition duration-200 absolute top-0 left-0 w-full h-full flex items-center justify-center"
@click.prevent="remove(item.id)">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-16 h-16">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<span class="text-2xl" x-text="item.name"></span>
</div>
</div>
</template>
</div>
</template>
</div>
Setup
import autoAnimate from "@formkit/auto-animate";
import Alpine from "alpinejs";
window.Alpine = Alpine;
Alpine.directive('animate', el => {autoAnimate(el)});
Alpine.start();
That's it. Two lines, one to import and one for the new directive.
After
Sprinkle in that new AlpineJs directive and an `x-animate` attribute on the list and checkout the results. Pretty crazy upgrade for 2 lines of code. Overall it added 15KB of javascript (4KB gzipped). Completely worth it.
Final word
From the AutoAnimate website:
**********
AutoAnimate is fundamentally a single function — autoAnimate
— that accepts a parent element. Automatic animations will be applied to the parent element and its immediate children. Animations are specifically triggered when one of three events occurs:
- A child is added in the DOM.
- A child is removed in the DOM.
- A child is moved in the DOM.
**********
That's really the only thing to keep in mind when mixing it into AlpineJs. It won't work with `x-show` if you are hiding/showing elements, you need to use `x-if` with a `template` so DOM elements are actively being added/removed from some parent element.