A quick demo
AutoAnimate adds automatic animations to your JavaScript applications with a single line of code. Here's the same list component with and without AutoAnimate applied to the wrapping element:
That's a fairly notable improvement in UX for no additional developer effort! š
Installation
Install using your package manager of choice to add @formkit/auto-animate
to your project:
Aaaaand, youāre done! That was fast. š
If you are using React, you can use the useAutoAnimate
hook. If you are using Vue, you can use the v-auto-animate
directive.
Usage
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.
Letās see what this looks like in practice. For now we'll use the autoAnimate
function directly. React and Vue users ā youāll get some additional syntactic sugar later on ā but for now let's learn the fundamentals:
import { useState, useRef, useEffect } from 'react'
import autoAnimate from '@formkit/auto-animate'
const Dropdown = () => {
const [show, setShow] = useState(false)
const parent = useRef(null)
useEffect(() => {
parent.current && autoAnimate(parent.current)
}, [parent])
const reveal = () => setShow(!show)
return <div ref={parent}>
<strong className="dropdown-label" onClick={reveal}>Click me to open!</strong>
{ show && <p className="dropdown-content" >Lorum ipsum...</p> }
</div>
}
export default Dropdown
Click me to open!
Too easy! A gentle, smooth shift without adding any transition classes or custom CSS. This is a notable upgrade for end users with minimal developer effort required. Checkout the examples to see other use cases.
Tips for success
- Itās still ok to use other kinds of transitions. For example, if you are making stylistic changes with just CSS (such as a hover effect), then use standard CSS transitions for these kinds of styling tweaks.
- Animations are only triggered when immediate children of the parent element (the one you passed to
autoAnimate
) are added, removed, or moved. - The parent element will automatically receive
position: relative
if it is statically positioned. Keep this in mind when writing your styles. - Sometimes flexbox layouts donāt resize their children immediately. A child with a
flex-grow: 1
property waits for the surrounding content before snapping to its full width. AutoAnimate doesnāt work well in these cases, but if you give the element a more explicit width it should work like a charm.
Configuration
AutoAnimate is intended to be used with zero-configuration. We believe the default configuration falls in line with the projectās objective: AutoAnimateās goal is to substantially improve an applicationās user-experience without impacting the developerās implementation time or performance budget. That said, some minor configuration options are available. AutoAnimate allows you to pass a second argument to autoAnimate
with the following options:
autoAnimate(el, {
// Animation duration in milliseconds (default: 250)
duration: 250,
// Easing for motion (default: 'ease-in-out')
easing: 'ease-in-out'
})
If your projectās specific requirements make it necessary to dramatically change the default animations, then you should check out the plugins documentation.
React hook
React users can use the hook useAutoAnimate
by importing it from @formkit/auto-animate/react
. This hook returns a ref to apply to the parent element:
import { useState } from 'react'
import { useAutoAnimate } from '@formkit/auto-animate/react'
const App = function () {
const [items, setItems] = useState([0, 1, 2])
const [parent] = useAutoAnimate(/* optional config */)
const add = () => setItems([...items, items.length])
return <>
<ul ref={parent}>
{items.map(
item => <li key={item}>{ item }</li>
)}
</ul>
<button onClick={add}>Add number</button></>
}
export default App
Vue directive
Vue users can globally register the v-auto-animate
directive. This makes adding transitions and animations as easy as applying an attribute. Import the Vue plugin from @formkit/auto-animate/vue
and register it with your Vue app:
Once youāve registered the plugin, it can be applied anywhere in your application by adding the v-auto-animate
directive to the parent element:
<script setup>
import { ref } from 'vue'
const items = ref(["š","š","š","š","š", ... ])
function removeItem(toRemove) {
items.value = items.value.filter((item) => item !== toRemove)
}
</script>
<template>
<h5>Click emojis to remove them.</h5>
<ul v-auto-animate>
<li
v-for="item in items"
:key="item"
@click="removeItem(item)"
>
{{ item }}
</li>
</ul>
</template>
Click emojis to remove them.
Vue users can pass options by directly setting the directiveās value <ul v-auto-animate="{ duration: 100 }">
Examples
Add and remove fruits from a list. Note that fruits are placed at random locations in the list to simulate injecting items rather than just pushing and unshifting.
Simulates showing a form to add an event to a list of event cards. Notice that it pushes it to the front of the list and all the cards animate to their destination, and the parent element (invisible) resizes smoothly to accommodate.
An important feature of AutoAnimate is that it operates on both the x and y axis. Items that are moved in the DOM from one location to another, or are wrapping at the end of a line will automatically be translated to their respective position.
Weāve all had to create accordions before. Pretty easy on the surface, but adding motion to the open/close sequence can be frustrating to say the least, and if you hack it together using max-height
transitions, you are sure to lose your easing. No more!
- We needed a way to animate DOM elements without adding to the virtual DOM in Vue and React. And it turned out our solution was gonna work great for lots of other use cases as well.
You donāt have to use FormKit to use AutoAnimate, but if you are a FormKit user, there are some neat things you can do. For example, you can use AutoAnimate to animate validation messages being added and removed from an input:
Plugins
While AutoAnimate is intended to be used with its zero-config defaults, some users may need to replace the default animation keyframes with custom ones. To do this, provide a function as the second argument of the autoAnimate
function. This function will be called before every animation and must return a KeyframeEffect
.
Here we will create a new set of keyframes for the add
, remove
and remain
actions that overshoot their destinations to create a "bouncy" animation effect.
import autoAnimate, { getTransitionSizes } from '@formkit/auto-animate'
autoAnimate(parentElement, (el, action, oldCoords, newCoords) => {
let keyframes
// supply a different set of keyframes for each action
if (action === 'add') {
keyframes = [
{ transform: 'scale(0)', opacity: 0 },
{ transform: 'scale(1.15)', opacity: 1, offset: 0.75 },
{ transform: 'scale(1)', opacity: 1 }
]
}
// keyframes can have as many "steps" as you prefer
// and you can use the 'offset' key to tune the timing
if (action === 'remove') {
keyframes = [
{ transform: 'scale(1)', opacity: 1 },
{ transform: 'scale(1.15)', opacity: 1, offset: 0.33 },
{ transform: 'scale(0.75)', opacity: 0.1, offset: 0.5 },
{ transform: 'scale(0.5)', opacity: 0 }
]
}
if (action === 'remain') {
// for items that remain, calculate the delta
// from their old position to their new position
const deltaX = oldCoords.left - newCoords.left
const deltaY = oldCoords.top - newCoords.top
// use the getTransitionSizes() helper function to
// get the old and new widths of the elements
const [widthFrom, widthTo, heightFrom, heightTo] = getTransitionSizes(el, oldCoords, newCoords)
// set up our steps with our positioning keyframes
const start = { transform: `translate(${deltaX}px, ${deltaY}px)` }
const mid = { transform: `translate(${deltaX * -0.15}px, ${deltaY * -0.15}px)`, offset: 0.75 }
const end = { transform: `translate(0, 0)` }
// if the dimensions changed, animate them too.
if (widthFrom !== widthTo) {
start.width = `${widthFrom}px`
mid.width = `${widthFrom >= widthTo ? widthTo / 1.05 : widthTo * 1.05}px`
end.width = `${widthTo}px`
}
if (heightFrom !== heightTo) {
start.height = `${heightFrom}px`
mid.height = `${heightFrom >= heightTo ? heightTo / 1.05 : heightTo * 1.05}px`
end.height = `${heightTo}px`
}
keyframes = [start, mid, end]
}
// return our KeyframeEffect() and pass
// it the chosen keyframes.
return new KeyframeEffect(el, keyframes, { duration: 600, easing: 'ease-out' })
}))
We can use our newly defined keyframes in any previous example to see the effect it has. Here's our previous list example with the "bouncy" keyframes applied to it:
List example with "bouncy" keyframes
Why not...?
There are loads of Animation libraries available for JavaScript and each has its place. AutoAnimate is not a traditional animation library ā think of it more as "Prettier for motion" ā it is an easy-to-implement standard you can quickly apply to any project.
AutoAnimateās goal is to smooth out changes to the DOM that are otherwise confusing to end-users. For example, when a user sorts a list with no animations, it is difficult to visualize how the items in the list have actually changed ā but with AutoAnimate the changes suddenly make intuitive sense. AutoAnimate was made to solve this category of problem via a drop-in solution with zero-config.
Support us
Is AutoAnimate saving you time? Please consider supporting our open-source efforts with a recurring or one-time donation! š