Layout group
<AnimeLayoutGroup> wraps elements whose size or position changes, and
animates them to the new layout with AnimeJS
layout. It is the component
form of useAnimeLayout.
Usage
List the values that change the layout in deps. When one changes, the
children slide to their new places, and new ones fade in:
nanime wraps AnimeJS v4 in Vue composables and components for Nuxt. It resolves template refs to elements, rebuilds animations when their inputs change, and reverts them when the component unmounts.
const questions = [
{ title: 'What is nanime?', answer: '...' },
{ title: 'Does it work with SSR?', answer: '...' },
{ title: 'Which AnimeJS version does it use?', answer: '...' },
]
const open = ref<number | null>(0)
function toggle(index: number) {
open.value = open.value === index ? null : index
}
<template>
<AnimeLayoutGroup :deps="[open]" class="flex w-full max-w-md flex-col gap-2">
<div
v-for="(question, index) in questions"
:key="question.title"
class="rounded-lg bg-primary text-inverted"
>
<button type="button" class="..." @click="toggle(index)">
<span>{{ question.title }}</span>
<UIcon
:name="open === index ? 'i-ph-minus-bold' : 'i-ph-plus-bold'"
class="size-4 shrink-0"
/>
</button>
<p v-if="open === index" class="px-4 pb-4 text-sm">
{{ question.answer }}
</p>
</div>
</AnimeLayoutGroup>
</template>
| Prop | Type | Default | Description |
|---|---|---|---|
deps | unknown[] | Values or getters that trigger a layout animation when they change, including nested changes. | |
shallow | boolean | false | Animate only when an entry of deps is replaced, not when something nested inside it changes. |
elements | AnimeLayoutElements | every element inside | The elements that animate their own position and size: a selector, elements, components, or a list. |
layoutOptions | AutoLayoutParams | { ease: spring({ bounce: 0.15, duration: 300 }) } | AnimeJS createLayout() params, such as duration or ease. Setting either one replaces the spring. Use elements for children. |
tag | string | 'div' | Element rendered around the children. |
completeOnTabHidden | boolean | false | Jump running animations to their end when the browser tab is hidden. |
Without deps, every re-render of the group measures every child and
animates, even when nothing moved, such as when a parent passes a new
object or array prop.
Choosing between the two groups
<AnimeLayoutGroup> and
<AnimeTransitionGroup> both take
deps and shallow, but they animate different changes:
<AnimeTransitionGroup> | <AnimeLayoutGroup> | |
|---|---|---|
| Built for | v-for items that enter, leave and reorder | Mounted elements that change size or position |
| Enter and leave | enterAnimation and leaveAnimation run on each item | v-show fades an element, v-if removes it at once |
deps | Adds triggers on top of list changes. :deps="[]" adds none | The only trigger |
| Timing | moveAnimation: duration, delay and ease | layoutOptions: any AnimeJS createLayout() param |
| What moves | Every element inside the group | Every element inside, or the ones elements picks |
Choosing which elements move
By default every element inside the group moves on its own, down to the
text inside a card. Pass elements to move only the cards:
<template>
<AnimeLayoutGroup :deps="[view]" elements=".card">
<div v-for="item in items" :key="item.id" class="card">
<h3>{{ item.title }}</h3>
</div>
</AnimeLayoutGroup>
</template>
elements, as in ".card, .card h3", to make it
slide. See the
AnimeJS layout gotchas.elements. The
name is yours to pick:<template>
<AnimeLayoutGroup :deps="[view]" elements="[data-layout]">
<div v-for="item in items" :key="item.id" class="card" data-layout>
<h3 data-layout>{{ item.title }}</h3>
</div>
</AnimeLayoutGroup>
</template>
- An element removed with
v-ifvanishes at once. Usev-showto fade it out too. - A selector only matches inside its own group. The group still measures everything inside it, so wrap only what moves.
- For
v-foritems that enter and leave, use<AnimeTransitionGroup>.