auto-animate
A zero-config, drop-in animation utility that adds smooth transitions to any web app with a single line of code.
Repository Health
Technical Analysis
AutoAnimate is a small utility from the FormKit team that watches a parent element and automatically animates its children whenever they are added, removed, or reordered in the DOM. Instead of hand-writing enter/exit transitions or wiring up a full animation library, you call a single function on a container element and every child mutation — list items appearing, form fields toggling, cards being sorted — gets a smooth FLIP-style transition for free.
Under the hood it uses a MutationObserver to detect DOM changes and the native Web Animations API to run the transitions, so there are no CSS classes to manage and no animation state to track manually. It ships framework bindings for React, Vue, Solid, Preact, Angular, Svelte, Qwik, and Marko, plus a Nuxt module, so the same core engine is reachable through whichever component model a project already uses.
Because it operates directly on real DOM mutations rather than a virtual-DOM diff, AutoAnimate works even when elements are added or removed by code it doesn’t control — third-party widgets, non-React DOM manipulation, or plain vanilla JS — making it one of the few animation utilities that doesn’t require rewriting how a UI already manages its elements.
What You Get
- A single
autoAnimate(el, options)call that instruments a parent element and automatically animates add/remove/move mutations of its children - First-class bindings for React (
useAutoAnimate), Vue (v-auto-animatedirective anduseAutoAnimatecomposable), Solid, Preact, Angular, Svelte, and Qwik - A Marko custom tag and a Nuxt module for drop-in use in those ecosystems without extra glue code
- An
AnimationControllerreturned from every binding, exposingenable(),disable(), anddestroy()for runtime control over a given container - A plugin system (
AutoAnimationPlugin) that lets you supply customKeyframeEffectkeyframes for add/remove/remain instead of the default scale/opacity transition - Automatic respect for the user’s
prefers-reduced-motionsetting, with an explicit opt-out flag for cases where that’s not desired
Common Use Cases
- Animating list additions and removals (to-do lists, notification feeds, search results) without writing enter/exit CSS
- Smoothly reordering sortable lists or Kanban-style boards as items move between positions
- Adding polish to dropdowns, accordions, and toggled form sections that mount/unmount children
- Retrofitting motion onto an existing app’s DOM updates without restructuring how the app already renders lists
Under The Hood
Architecture
The core lives in a single src/index.ts module that keeps all instrumented-element state in WeakMaps and WeakSets keyed by DOM node (coordinates, sibling references, in-flight animations, intersection/mutation observers, per-element options) plus one non-weak Set tracking instrumented parent containers. Framework bindings (React, Vue, Solid, Preact, Angular, Qwik, Marko, plus a Nuxt module) are thin adapters that call this same core autoAnimate() function and wrap its returned AnimationController lifecycle in each framework’s own idioms — useState/useEffect in React, watchEffect/onBeforeUnmount in Vue, createSignal/onCleanup in Solid. Data flows from a MutationObserver detecting childList changes, through handleMutations/getElements resolving which elements were actually affected (including short-circuiting on comment-only mutations), into animate() branching into add/remain/remove based on existing WeakMap state, which drives FLIP-style transforms through the Web Animations API. Because every binding imports directly from the core module with no isolating adapter layer, a breaking change to the core’s public shape (autoAnimate, AnimationController) would immediately break all eight framework integrations at once.
Tech Stack
Written in strict-mode TypeScript targeting ES2019, compiled via a custom Rollup/unbuild pipeline driven through jiti (build/build.mjs, build/bundle.ts). The published package has zero runtime dependencies — every framework listed in devDependencies (React 19, Vue 3.5, Solid, Angular, Marko, Nuxt tooling) exists only to compile and test that framework’s binding, never to run the library itself. End-to-end and visual-regression testing runs on Playwright against a Vite-served docs/demo app, with pixelmatch/pngjs doing pixel-diffing for visual assertions. The project builds pure ESM output (type: module, .mjs files) with per-framework subpath exports (./vue, ./react, ./solid, etc.), each carrying independent type declarations, and ships releases through bumpp via GitHub Actions.
Code Quality
Testing is entirely Playwright-based end-to-end and visual specs (list/dropdown animation triggers, Vue v-if behavior, offscreen-element handling, a scroll-jump regression test, memory-leak checks gated behind a LEAK_STRICT env flag, and dedicated Marko SSR specs) rather than isolated unit tests of internal helpers like coordinate math or transition-size calculation. TypeScript strict mode is enabled project-wide and the core module is densely JSDoc-commented per internal function. Error handling is intentionally minimal and defensive — expected AbortErrors from cancelled Web Animations are swallowed in empty catch blocks rather than surfaced through a typed error path, which is a reasonable tradeoff for a DOM-observer library but does mean failure modes are largely implicit. No dedicated lint/format config is checked into the repo root, leaving TypeScript’s own strictness as the main consistency guardrail.
API Design
The entire public surface for the default case is one function call — autoAnimate(el) — with framework bindings reducing that further to a single hook or directive (useAutoAnimate(), v-auto-animate), which is unusually low ceremony compared to transition libraries that require explicitly authoring enter/exit states per element (React’s TransitionGroup, Vue’s <transition-group>). Its core novelty is deriving transitions purely from observed MutationObserver events rather than framework lifecycle hooks or virtual-DOM diffing, so it animates DOM changes made by any code touching that subtree — not just the framework binding installed — while still exposing a plugin escape hatch (a function returning a raw KeyframeEffect) for teams that need to fully customize the animation beyond the built-in scale/opacity/transform defaults.
Used by 10 apps in this directory
Cal.diy
Scheduling
The 100% MIT-licensed, community-driven scheduling platform — self-host your own booking infrastructure with no enterprise strings attached.
Formbricks
Forms Surveys · Marketing · Analytics
Open-source experience management platform for in-app, website, email, and link surveys — privacy-first and fully self-hostable.
Kener
Monitoring · Devops
Stunning, self-hosted status pages with real-time uptime monitoring, incident management, and multi-channel notifications in a single Docker container.
LobeHub
AI Assistants · Productivity · Automation
Your Chief Agent Operator — build, schedule, and collaborate with an entire AI team in one self-hostable workspace.
NewsNow
Bookmarks Archiving
Self-hostable news aggregator with an elegant column layout, GitHub OAuth, adaptive scraping intervals, and seamless Cloudflare D1 or SQLite persistence.
open-design
Design Tools
Local-first, open-source Claude Design alternative that turns your existing coding agent CLI into a full agentic design studio — with 259+ skills, 142+ design systems, and sandboxed artifact delivery across web, desktop, and mobile surfaces.
OpenSign
Digital Signiture
Self-host a full-featured DocuSign alternative with unlimited e-signatures, multi-signer workflows, and cryptographic PDF signing.
Trieve
AI Development · Search · Developer Tools
All-in-one self-hostable platform for hybrid search, RAG, recommendations, and analytics built on Rust and Qdrant.
undb
No Code Platforms · Databases
Self-hosted no-code database and BaaS that lets you manage structured data visually with multi-database support, formula fields, and auto-generated OpenAPI endpoints.