Skip to main content
Anime.js provides automatic layout transition animations using the FLIP (First, Last, Invert, Play) technique.

Auto Layout

The AutoLayout class animates layout changes automatically.

Basic Usage

import { AutoLayout } from 'animejs';

const layout = new AutoLayout('.container', {
  children: '.item',
  duration: 600,
  ease: 'out(3)'
});

// Make DOM changes
document.querySelector('.item').remove();

// Animate the layout change
layout.animate();

How It Works

  1. Record - Capture element positions before change
  2. Modify - Make your DOM changes
  3. Animate - Smoothly transition to new positions
const layout = new AutoLayout('.grid');

// Record current state
layout.record();

// Make changes (add, remove, reorder elements)
container.appendChild(newElement);

// Animate to new state
layout.animate();

Configuration

Children Selector

// Animate specific children
const layout = new AutoLayout('.container', {
  children: '.card'
});

// Animate all children
const layout = new AutoLayout('.container', {
  children: '*'
});

// Multiple selectors
const layout = new AutoLayout('.container', {
  children: ['.card', '.item', '.box']
});

Custom Properties

Animate additional CSS properties during transitions:
const layout = new AutoLayout('.container', {
  children: '.item',
  properties: [
    'backgroundColor',
    'borderRadius',
    'color',
    'fontSize',
    'boxShadow'
  ],
  duration: 800
});
By default, position, size, opacity, and basic visual properties are animated.

State Transitions

Enter Animation

Define how new elements appear:
const layout = new AutoLayout('.container', {
  children: '.item',
  enterFrom: {
    opacity: 0,
    scale: 0.8,
    translateY: 20,
    duration: 600,
    ease: 'out(3)'
  }
});

Leave Animation

Define how removed elements exit:
const layout = new AutoLayout('.container', {
  children: '.item',
  leaveTo: {
    opacity: 0,
    scale: 0.5,
    translateY: -50,
    duration: 400,
    ease: 'in(2)'
  }
});

Swap Animation

Transition state for elements changing size:
const layout = new AutoLayout('.container', {
  children: '.item',
  swapAt: {
    opacity: 0.5,
    scale: 0.95,
    duration: 300,
    ease: 'inOut(2)'
  }
});
swapAt
object
Intermediate state when elements change dimensions. Animation goes: current → swapAt → new

Complete Example

import { AutoLayout } from 'animejs';

const layout = new AutoLayout('.grid', {
  children: '.card',
  duration: 600,
  ease: 'out(3)',
  
  // New elements fade and slide in
  enterFrom: {
    opacity: 0,
    translateY: 30,
    scale: 0.9
  },
  
  // Removed elements shrink out
  leaveTo: {
    opacity: 0,
    scale: 0.8,
    translateY: -20
  },
  
  // Elements briefly dim during resize
  swapAt: {
    opacity: 0.6
  },
  
  // Track additional properties
  properties: ['backgroundColor', 'borderRadius'],
  
  // Callbacks
  onComplete: (timeline) => {
    console.log('Layout animation complete');
  }
});

// Usage
function addCard() {
  layout.record();
  container.appendChild(createCard());
  layout.animate();
}

function removeCard(card) {
  layout.record();
  card.remove();
  layout.animate();
}

function reorderCards() {
  layout.record();
  // ... reorder logic
  layout.animate();
}

Timing Functions

Staggered Delays

const layout = new AutoLayout('.container', {
  children: '.item',
  delay: (el, i) => i * 50,
  duration: (el, i) => 400 + (i * 20),
  ease: (el, i) => i % 2 ? 'out(2)' : 'out(3)'
});

Per-State Timing

const layout = new AutoLayout('.container', {
  children: '.item',
  duration: 600,
  
  enterFrom: {
    opacity: 0,
    duration: 800,  // Slower enter
    delay: (el, i) => i * 100
  },
  
  leaveTo: {
    opacity: 0,
    duration: 300,  // Faster leave
    ease: 'in(2)'
  }
});

Animation Control

Layout animations return timelines:
const layout = new AutoLayout('.container');

layout.record();
// ... make changes
const timeline = layout.animate();

// Control the timeline
timeline.pause();
timeline.seek(500);
timeline.reverse();

Custom Animation

Provide animation parameters when calling animate():
const layout = new AutoLayout('.container');

layout.record();
// ... changes

layout.animate({
  duration: 1000,
  ease: 'inOut(4)',
  delay: (el, i) => i * 50,
  onComplete: () => {
    console.log('Done');
  }
});

Scroll Integration

import { AutoLayout, onScroll } from 'animejs';

const layout = new AutoLayout('.container');

layout.record();
// ... make changes

const timeline = layout.animate({
  autoplay: onScroll({
    target: '.container',
    sync: true
  })
});

Cleanup

const layout = new AutoLayout('.container');

// Later...
layout.revert();
Call revert() before destroying the container element to clean up internal references and prevent memory leaks.

Common Patterns

List Reordering

const listLayout = new AutoLayout('.todo-list', {
  children: '.todo-item',
  duration: 400,
  ease: 'out(3)'
});

function reorder(oldIndex, newIndex) {
  listLayout.record();
  const item = list.children[oldIndex];
  list.insertBefore(item, list.children[newIndex]);
  listLayout.animate();
}

Grid Filtering

const gridLayout = new AutoLayout('.grid', {
  children: '.card',
  leaveTo: {
    opacity: 0,
    scale: 0.5
  }
});

function filter(category) {
  gridLayout.record();
  
  cards.forEach(card => {
    if (card.dataset.category === category) {
      card.style.display = '';
    } else {
      card.style.display = 'none';
    }
  });
  
  gridLayout.animate();
}

Accordion

const accordion = new AutoLayout('.accordion', {
  children: '.panel',
  swapAt: {
    opacity: 0.5
  },
  duration: 500
});

function toggle(panel) {
  accordion.record();
  panel.classList.toggle('expanded');
  accordion.animate();
}
const modalLayout = new AutoLayout('body', {
  children: '.modal',
  enterFrom: {
    opacity: 0,
    scale: 0.9,
    translateY: -50
  },
  leaveTo: {
    opacity: 0,
    scale: 0.95,
    translateY: 50
  }
});

function openModal() {
  modalLayout.record();
  document.body.appendChild(modal);
  modalLayout.animate();
}

Performance Tips

Only track properties you need to animate:
new AutoLayout('.container', {
  properties: ['opacity'] // Minimal tracking
});
Add will-change to elements that will be animated:
.item {
  will-change: transform, opacity;
}
Make all DOM changes before calling animate():
layout.record();
// Batch all changes here
element1.remove();
element2.appendChild(newChild);
element3.classList.add('active');
// Then animate once
layout.animate();
The library handles this automatically, but avoid reading layout properties between record() and animate().

Browser Support

Layout animations work in all modern browsers with ResizeObserver support.

Limitations

  • SVG elements are not supported
  • Fixed and absolute positioning may require absoluteCoords option
  • Nested layouts need separate instances
  • CSS transitions on tracked elements should be disabled during animations

Build docs developers (and LLMs) love