auto-animate

GitHub

A zero-config, drop-in animation utility that adds smooth transitions to your web app. You can use it with React, Vue, or any other JavaScript application.

AI Prompts & Endpoints
CodeWiki Knowledge Base

Repository: formkit/auto-animate


Stars: 13794

.cursorrules

Project overview


- Purpose: Zero-config motion for DOM list changes. Given a parent element, automatically animates its immediate children when they are added, removed, or moved.
- Core entry: src/index.ts exports autoAnimate(el, configOrPlugin) and types, plus a Vue directive vAutoAnimate.
- Framework adapters: Thin wrappers providing hooks/directives for Vue, React, Solid, Preact, Angular, Qwik under src/<framework>/index.ts.
- Build: TS β†’ ESM via Rollup; built artifacts land in dist/. Package exports map serves index.mjs and framework subpaths.

Mental model (how it works)


- Observers
- MutationObserver on the parent watches childList changes. For each mutation, getElements collects the parent and child elements that changed (including removed ones), tagging each with a non-enumerable target marker __aa_tgt.
- ResizeObserver on document.documentElement (root) and on each observed element updates cached positions when sizes change.
- IntersectionObserver is created per element to detect position changes while scrolling; a dynamic rootMargin derived from the last known coordinates triggers recalculation. Occasional low-priority polling backs this up.
- State tracking (all with WeakMap/WeakSet to avoid leaks)
- coords: last known absolute coordinates adjusted for nearest scrolling ancestor.
- siblings: prev/next references for elements removed from the DOM so they can be temporarily reinserted for exit animations.
- animations: current Web Animations API Animation per element.
- intersections, intervals, debounces: observers/intervals/timers per element.
- options: the per-parent config or plugin; enabled: parents with animations enabled.
- Deciding what to animate
- animate(el) selects one of: add, remain, or remove based on whether the element has cached coordinates and whether it’s still connected.
- Flags: __aa_new marks newly reinserted nodes to ensure their next cycle is treated as an entry; __aa_del marks nodes currently animating out.
- Effects
- Default behavior uses Web Animations API: add scales/ fades in; remain uses FLIP-style transforms (translate from old to new), also animates width/height deltas respecting box-sizing; remove temporarily re-inserts the node near its original position, absolutely positions it, and scales/fades out.
- Plugins: if config is a function, it’s treated as an AutoAnimationPlugin. Plugin functions return a KeyframeEffect or [KeyframeEffect, { styleReset | false }]. The library will construct and play an Animation from the effect and handle optional style resets.
- Scroll handling
- Coordinates are absolute plus the nearest scrollable ancestor’s offset.
- During removal at page bottom, the library compensates for scroll jumps by snapshotting pre/post window scroll and performing a manual scroll animation to match the configured duration/easing.
- Options & accessibility
- Defaults: { duration: 250, easing: 'ease-in-out' }.
- Respects prefers-reduced-motion: reduce unless disrespectUserMotionPreference: true or a plugin is used.
- AnimationController controls enable/disable per parent.

Public API surface


- Default export: autoAnimate(el: HTMLElement, config?: Partial<AutoAnimateOptions> | AutoAnimationPlugin): AnimationController
- Types: AutoAnimateOptions, AutoAnimationPlugin, AutoAnimationPluginOptions, AnimationController.
- Vue: vAutoAnimate directive, autoAnimatePlugin, useAutoAnimate hook.
- React/Preact: useAutoAnimate hook returns [refCallback | refObject, setEnabled].
- Solid: createAutoAnimate and createAutoAnimateDirective.
- Angular: AutoAnimateDirective ([auto-animate]).
- Qwik: useAutoAnimate returns [Signal<HTMLElement>, setEnabledQRL].
- Nuxt: module that registers the Vue directive and auto-imports autoAnimate and useAutoAnimate.

Key invariants and conventions


- Do not mutate children beyond adding style resets for exit animations; remove those styles in cleanUp.
- All per-node state is in WeakMaps/Sets to prevent memory leaks; never store strong references to DOM nodes outside these registries.
- Only immediate children of the target parent are animated; traversal utilities (forEach) visit the parent first, then its children.
- Always schedule position updates after animations finish (animation.addEventListener('finish', updatePos)), and debounce updates using the current duration (or 500ms for plugins).
- When computing size deltas, use getTransitionSizes to respect box-sizing: content-box padding/borders.
- Tagging properties __aa_tgt, __aa_del, __aa_new are non-enumerable and must be defined via Object.defineProperty.
- Core must remain framework-agnostic; adapters import from ../index only.

Files and what lives where


- src/index.ts: All core logic and types; also exports a Vue directive for convenience.
- src/debug-utils.ts: Optional dev-time helpers (e.g., drawMargins) to visualize IntersectionObserver margins.
- src/{vue,react,preact,solid,angular,qwik}/index.ts: Framework bindings.
- src/nuxt/{module.ts,runtime/plugin.ts}: Nuxt module and runtime plugin.
- docs/: Vite/Vue demo and docs site.
- cypress/: E2E tests for docs/examples.
- rollup.config.js: Build configuration; FRAMEWORK, DECLARATIONS, and MIN env flags control outputs.
- package.json: Exports map and scripts.

How to run


- Install: pnpm install.
- Docs (playground): pnpm dev (runs Vite in docs/).
- Build library: pnpm build (runs node ./build/build.mjs).
- Build docs: pnpm build-docs.
- Cypress: in one terminal pnpm cypress:server (docs dev server), in another pnpm cypress:open.
- Nuxt playground: pnpm nuxt:dev (if playground present).

Adding or changing behavior


- Modify default animations: adjust add, remain, remove in src/index.ts. Maintain invariants around style resets and cleanup. Ensure updatePos is called after each animation to keep coords fresh and observers connected.
- Plugins: The plugin signature is the extension point. If adding plugin options, keep the tuple return backwards-compatible. Only treat config as plugin when it’s a function.
- Performance: Be careful changing IntersectionObserver threshold/rootMargin; it’s tuned to avoid excessive updates and to catch movement. Use lowPriority for non-critical updates.
- Accessibility: Keep the prefers-reduced-motion guard; only bypass if explicitly configured.

Common pitfalls


- Forgetting to re-observe or update positions after animation causes stale coords and erratic flips. Always call updatePos on finish.
- Mutating layout-affecting styles outside of animations can desync computed sizes. Prefer transform/opacity for motion; animate width/height only through getTransitionSizes path.
- Not accounting for scroll in coords leads to incorrect deltas. Always use getCoords and getScrollOffset utilities.
- Exit animations must temporarily reinsert the element and absolutely position it; skipping style reset or cleanup leaks styles into future reuses of that node.

Coding style


- TypeScript strict; avoid any in public APIs.
- Clear, descriptive names; early returns for edge cases.
- Keep core free of framework-specific imports.
- Comments explain β€œwhy” when logic is subtle (e.g., scroll compensation), not trivial β€œhow”.

Testing guidance


- Prefer adding example scenarios in docs/ for manual verification.
- E2E flows live in cypress/integration; add/extend specs that exercise add/remove/reorder, variable heights, nested scroll containers, and reduced-motion.

Triage checklist for bugs


- Repro in docs/ with a minimal list/grid.
- Check if prefers-reduced-motion disabled animations.
- Verify parent element has position not left static when required (core sets to relative if static).
- Inspect coords freshness (use updatePos logs or debug-utils).
- Confirm scroll compensation path when removing near viewport bottom.

External APIs used


- Web Animations API (Element.prototype.animate, Animation, KeyframeEffect).
- MutationObserver, ResizeObserver, IntersectionObserver.
- requestIdleCallback (fallback to requestAnimationFrame).

Release & packaging


- Build uses Rollup; env flags:
- FRAMEWORK=index|vue|react|preact|solid|angular|qwik controls entry file.
- DECLARATIONS=true emits types only.
- MIN=true emits minified .min.js.
- package.json#exports serves subpath entries (./vue, ./react, etc.).

Security & SSR


- Core guards on window and ResizeObserver presence; no-ops in unsupported/non-browser contexts.
- Vue directive exposes getSSRProps to be SSR-safe.

Docs site (Vite + Vue SSG)


- Architecture: A separate Vue 3 SPA in docs/ built and statically generated with Vite + vite-ssg. It produces a fully static site (no server required at runtime).
- Entry points:
- docs/index.html is the HTML shell that loads /src/main.ts.
- docs/src/main.ts uses ViteSSG(App, { routes }, setup) to register routes and install the FormKit Vue plugin.
- docs/src/App.vue renders a RouterView and site chrome (header/footer/announcement).
- Routing:
- Routes are declared in docs/src/main.ts via an array of RouteRecordRaw.
- Current routes: / β†’ PageHome.vue, /lists β†’ PageList.vue, /tests β†’ PageTests.vue, /tests-keep-alive β†’ PageTestKeepAlive.vue (some loaded via dynamic import for code-splitting).
- vite.config.ts sets ssgOptions.includeAllRoutes = true, so all known routes are pre-rendered during vite-ssg build.
- Content structure:
- docs/src/pages/: top-level pages composing sections and examples.
- docs/src/sections/: content sections used on the home page (installation, usage, examples, plugins, why).
- docs/src/components/: UI components (navigation, header/footer, icons, code example wrapper, etc.).
- docs/src/examples/: live examples/demos per framework, showing how to use @formkit/auto-animate in practice.
- Global styles under docs/assets/ (main.css, variables.css, prism.css), images under docs/assets/img/, and fonts under docs/assets/fonts/.
- Third-party integrations:
- @vitejs/plugin-vue for Vue SFCs.
- vite-ssg for static generation.
- @formkit/vue plugin registered in the SSG setup.
- PrismJS loaded via <script> in index.html for code highlighting; GitHub buttons via their script; a site script tag is included for analytics.
- Dev/build commands (from package.json):
- Dev playground: pnpm dev β†’ cd docs && vite --config=./vite.config.ts.
- Static build: pnpm build-docs β†’ cd docs && vite-ssg build --config=./vite.config.ts (outputs static assets to the default Vite output directory).
- Cypress E2E: start docs dev server pnpm cypress:server (port 5555), then run pnpm cypress:open.
- How examples reference the library:
- Examples import from @formkit/auto-animate (and subpaths) to demonstrate public API usage. During local development, ensure the library is built (pnpm build) if the examples need the latest compiled artifacts; otherwise Vite may resolve from the package cache.
- Deployment:
- The generated static output can be deployed to any static host (Netlify, Cloudflare Pages, GitHub Pages). No server logic is required.


README.md

<img width="300" height="37" alt="AutoAnimate Logo" src="https://cdn.formk.it/web-assets/logo-auto-animate.svg" >

!Latest Build !GitHub Sponsors

Add motion to your apps with a single line of code.

AutoAnimate is a zero-config, drop-in animation utility that adds smooth transitions to your web app. You can use it with Vue, React, Solid or any other JavaScript application.

<a href="https://auto-animate.formkit.com"><img width="180" height="42" src="https://cdn.formk.it/web-assets/read-docs-auto-animate-v2.svg" alt="Examples & Docs"></a>

With one line of code, you can improve your interfaces, for example:

<a href="https://auto-animate.formkit.com">
<img src="https://cdn.formk.it/web-assets/motion.gif" alt="Simple example of AutoAnimation motion">
</a>

Installation

Install using your package manager of choice.

bash

yarn


yarn add @formkit/auto-animate

npm


npm install @formkit/auto-animate

pnpm


pnpm add @formkit/auto-animate

Boom! Done. That was fast! πŸ‡

Usage

πŸ“– View the documentation site for usage instructions.

Examples

πŸ“– View the documentation site for examples.

Plugins

πŸ“– View the documentation site for plugin instructions.

Support us

Is AutoAnimate saving you time?

Please consider supporting us with a recurring or one-time donation! πŸ™

Contributing

Thank you for your willingness to contribute to this free and open source project! When contributing, consider first discussing your desired change with the core team via <a href="https://github.com/formkit/auto-animate/issues">GitHub issues</a>, <a href="https://discord.gg/SHYT8pyeNm">Discord</a>, or other method.