Web Animations API vs Framer Motion Which One Should You Use in 2026
Author
Muhammad Awais
Published
May 20, 2026
Reading Time
15 min read
Views
19.6k

Animation in React apps sits at an uncomfortable crossroads in 2026. Framer Motion is the dominant library installed, imported, and forgotten about until it shows up as the third-largest entry in your bundle analyzer. The Web Animations API is the browser-native alternative that most developers know exists but have never seriously evaluated. Motion One is the newer challenger that wraps WAAPI in a friendly API and clocks in at a fraction of Framer Motion's size. This guide cuts through the marketing and benchmarks to tell you exactly which tool belongs in which situation and what the real performance and DX tradeoffs look like in a production Next.js app.
The State of Web Animation in 2026
Three forces have shifted the animation landscape significantly over the last two years. First, the View Transitions API shipped in all major browsers and introduced a declarative, browser-native way to animate between page states and DOM changes with zero JavaScript required for the simplest cases. Second, the scroll-driven animations CSS spec landed, enabling scroll-linked animations with no scroll event listeners and no JavaScript at all. Third, Framer Motion's maintainers released Motion (formerly Motion One), a smaller, WAAPI-based library that separates the lightweight animation engine from the React-specific hooks.
The result is that the old binary CSS animations or Framer Motion is now a four-way split: pure CSS (including scroll-driven and View Transitions), the Web Animations API directly, Motion (the lightweight engine), and Framer Motion's full React integration. Each sits at a different point on the capability-versus-bundle-size curve, and choosing the wrong one for the wrong job is the most common animation mistake in production Next.js apps today.
The decision framework is not complicated, but it requires knowing what each tool actually costs and what it uniquely provides. Start there before touching your package.json.
What the Web Animations API Actually Is
The Web Animations API WAAPI is a JavaScript API built into the browser that gives you programmatic control over CSS animations. It is not a library. It is not a dependency. It ships with Chrome, Firefox, and Safari and has had cross-browser support since 2022 when Safari filled the last major gap. The core API looks like this:
const animation = element.animate(
[
{ opacity: 0, transform: "translateY(16px)" },
{ opacity: 1, transform: "translateY(0)" },
],
{
duration: 300,
easing: "cubic-bezier(0.4, 0, 0.2, 1)",
fill: "forwards",
}
);
// Fully controllable
animation.pause();
animation.reverse();
animation.currentTime = 150; // seek to midpoint
await animation.finished; // Promise resolves on completionEvery WAAPI animation runs on the browser's compositor thread by default the same thread that handles CSS transitions and @keyframes. For opacity and transform, this means the animation is completely decoupled from the main JavaScript thread. Your app can be executing expensive React renders, parsing JSON, or running a large sort and the animation does not skip a frame. This is the fundamental performance advantage that no JavaScript animation library that runs on the main thread can match.
The drawbacks of raw WAAPI are equally real. There is no React integration you are writing imperative DOM manipulation code in a declarative React world. There is no layout animation support animating an element from one position to another across a layout change requires manual FLIP logic. There is no automatic stagger, no drag, no spring physics. For simple, performance-critical animations, WAAPI is the right choice. For complex, interactive, layout-aware animations, you will spend more time rebuilding what Framer Motion gives you than you save on bundle size.
Framer Motion What You Are Actually Paying For
Framer Motion's full React package weighs in at around 47kb gzipped as of 2026. That is not a small number it is larger than React itself. But it is also not random bloat. The bundle includes a spring physics engine, a layout animation system that handles FLIP automatically, shared layout animations across route transitions, drag and gesture handling with velocity-based release, AnimatePresence for exit animations, and a full declarative API that integrates with React's state and lifecycle model.
The layout animation system alone is worth understanding. When you wrap elements with layout prop in Framer Motion, it measures the element's position before and after a React state change, calculates the delta, and animates the difference using a transform so the browser never needs to recalculate layout during the animation itself. Implementing this from scratch the FLIP technique is a dozen lines of careful code that most developers get wrong on the first attempt. Framer Motion makes it one prop.
AnimatePresence solves a problem unique to React: animating elements out of the DOM when they unmount. In React, when a component unmounts, it is gone instantly. There is no native way to play an exit animation before the element is removed. Framer Motion defers the unmount, plays the exit animation, and then removes the element. Building this behavior without the library requires either a state machine that tracks "exiting" elements or a library like React Transition Group neither is as ergonomic.
The honest case against Framer Motion is not that it does these things badly. It is that most apps use 10 percent of what it provides while paying the full 47kb bundle cost. A fade-in on scroll and a button hover state do not require spring physics, drag handling, or shared layout animations. They require opacity and transform on a composited layer, which WAAPI or a CSS transition can provide at zero bundle cost.
Motion (the Lightweight Engine) The Middle Ground
Motion — the package previously called Motion One, now published as the motion package with a separate motion/react entry point is the same team's answer to the bundle size criticism. The core engine uses WAAPI under the hood, adds spring physics and stagger on top, and comes in at around 18kb gzipped for the React integration. The API is intentionally similar to Framer Motion, so migration is mostly a find-and-replace of import paths.
What Motion gives up compared to full Framer Motion: the layout animation system, AnimatePresence, and shared layout animations across routes. These are the features that justify the full library. If you do not need any of them, Motion is the correct choice you get a clean declarative API, spring physics, stagger, and scroll-linked animation utilities at roughly a third of the weight.
The practical import difference: import {"{ motion }"} from "framer-motion" versus import {"{ motion }"} from "motion/react". The JSX is identical. The bundle cost is not.
The New CSS-Native Options You Should Know
Two CSS specifications that matured in 2024 and 2025 eliminate the need for JavaScript for a class of animations that developers were previously reaching for libraries to handle.
Scroll-driven animations let you link an animation's progress to the scroll position of the page or a scrollable container entirely in CSS. What previously required an Intersection Observer, a scroll event listener, and a debounce function now looks like this:
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.card {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 30%;
}This runs entirely on the compositor thread. No JavaScript. No library. No bundle cost. Browser support as of May 2026 covers Chrome, Edge, and Firefox Safari support is partial, so a progressive enhancement approach is the safe choice for now.
View Transitions API handles the other long-painful case: animating between pages or major DOM state changes. In Next.js App Router, you can enable view transitions with a few lines of configuration and get smooth, browser-native crossfades and morph animations between page navigations without any animation library at all. For the majority of "make page transitions feel smooth" requirements, this is now the correct answer.
Both of these CSS-native options have a meaningful implication for Core Web Vitals: because they run off the main thread entirely, they cannot contribute to INP (Interaction to Next Paint) regressions the way JavaScript-driven animations can. Every millisecond of animation work you move off the main thread is a millisecond that cannot block a user interaction from being processed. The relationship between animation approach and INP scores is direct, measurable, and often underestimated. The full techniques for diagnosing and fixing INP in Next.js are covered in our guide on fixing INP Core Web Vitals in Next.js, and the broader optimization picture is in our post on advanced Core Web Vitals and mobile optimization in Next.js.
The Decision Framework Which Tool for Which Job
Given the full landscape, the decision tree is straightforward once you know what each tool costs and provides.
Use pure CSS (transitions + keyframes + scroll-driven) when the animation is purely decorative, does not depend on JavaScript state, and the target browsers support the required spec. Hover effects, loading spinners, scroll-fade-in effects, page transition crossfades all of these are pure CSS territory in 2026. Zero bundle cost, runs on the compositor, works before JavaScript hydrates.
Use WAAPI directly when you need JavaScript-driven animation with precise programmatic control seeking, reversing, pausing mid-animation in response to events but do not need spring physics, stagger, or React integration. Game UI elements, custom audio visualizers, canvas-adjacent DOM animations. The zero-dependency cost is the advantage. The imperative code style is the tradeoff.
Use Motion (motion/react) when you want a declarative, React-friendly animation API with spring physics and stagger, but you do not need layout animations or exit animations on unmount. This covers the majority of marketing sites, landing pages, dashboards, and SaaS UIs that want polished micro-interactions without a heavy library. The 18kb cost is justifiable when you are replacing three or four different manual animation implementations.
Use full Framer Motion when you need layout animations, AnimatePresence, shared layout transitions across routes, or drag and gesture handling. These are features that have no practical equivalent in the other options. If your product has a Kanban board, a sortable list, a modal that animates from a card, or a drag-to-reorder UI, Framer Motion's layout system justifies the full bundle cost immediately.
The mistake to avoid is defaulting to full Framer Motion for everything because it is the most familiar option. Bundle size is a real user cost every extra kilobyte is parsing time on a mid-range mobile device, and animation libraries loaded on the main thread can contribute directly to INP regressions during initial load.
Using WAAPI in React Without Losing Your Mind
The main friction with WAAPI in React is that it requires a ref to a DOM element and imperative calls which feels out of place in a declarative component model. The pattern that works cleanly is a custom hook that accepts an animation config and returns a ref:
import { useEffect, useRef } from "react";
export function useFadeIn(duration = 300) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const animation = el.animate(
[
{ opacity: 0, transform: "translateY(12px)" },
{ opacity: 1, transform: "translateY(0)" },
],
{ duration, easing: "ease-out", fill: "forwards" }
);
return () => animation.cancel();
}, [duration]);
return ref;
}
// Usage
export function Card() {
const ref = useFadeIn(400);
return }>...
;
}
This pattern keeps the animation logic extracted, testable, and reusable and the component itself stays declarative. The cleanup function in the useEffect cancels the animation if the component unmounts during playback, which prevents the common memory leak of WAAPI animations running on detached DOM nodes.
For Intersection Observer-triggered animations the "animate when element enters the viewport" pattern the hook grows slightly to include an observer, but the structure remains the same: one ref, one effect, one cleanup. This replaces the most common Framer Motion use case in landing pages without adding a single byte to the bundle.
Bundle Size Impact and the Headless Component Context
Animation libraries do not live in isolation they are part of a total bundle that includes your UI component library, state management, form handling, and everything else the browser has to parse before your app is interactive. In the context of a modern Next.js app using a headless component architecture, the animation layer's size matters more, not less, because the components themselves are already leaner.
The shift from monolithic UI libraries toward headless, unstyled components Radix, Headless UI, shadcn was precisely about cutting the CSS and JavaScript overhead of pre-built component suites. If your component layer is already lean by design, importing a 47kb animation library to make a button fade in is architecturally inconsistent. The whole point of the headless approach is to pay only for what you use. The broader implications of that shift and the UI libraries that fit and do not fit within it are covered in our post on the decline of Material UI and the rise of headless components with Tailwind.
The consistent principle across component architecture, animation tooling, and everything else in a modern frontend stack is: know what you are buying before you install it. The bundlephobia check on every new dependency and the habit of auditing your bundle analyzer output monthly are the two practices that prevent animation library choices (and every other library choice) from accumulating into a slow, heavy app. Tools that automate this audit and surface regressions before they ship are part of the broader developer workflow covered in our breakdown of the lazy developer's workflow for Next.js that makes you 10x faster.
Practical Migration: From Framer Motion to Motion or WAAPI
If you have an existing app with full Framer Motion and want to right-size the animation layer, the migration path is incremental. Start by auditing which Framer Motion features you actually use. Open your codebase and search for AnimatePresence, layout prop usage, and layoutId. If none appear, you are not using the features that justify the full library.
If the audit comes back clean, switch the import from framer-motion to motion/react and install the motion package. The API surface for basic animations is nearly identical. Run your test suite, check the visual output, and uninstall framer-motion. In most projects this is a one-hour migration that saves 29kb gzipped.
For components that only use simple fade-in or slide-in effects typically hero sections, card grids, and feature sections replace the motion.div with a plain div and move the animation to a useFadeIn hook or a CSS scroll-driven rule. Each replacement removes that component from the Framer Motion import graph entirely, and with tree shaking, reducing usage reduces bundle output even before you drop the library.
Frequently Asked Questions
Is the Web Animations API production-ready in 2026?
Yes. WAAPI has full support in Chrome, Firefox, Edge, and Safari as of 2022 and has been stable since. The only features with partial support involve specific timing options like iterationComposite, which most production use cases do not need. For opacity, transform, color, and filter animations — the composited properties that matter most for performance WAAPI support is complete and reliable across all major browsers.
Does Framer Motion tree-shake well?
Framer Motion has improved its tree shaking significantly since version 10. If you only import motion and AnimatePresence, the bundler will not include the drag system or 3D transform utilities. But the core animation engine, spring physics, and React integration are always included when you use motion.div. The practical floor the minimum you pay when using any Framer Motion component is around 35kb gzipped. That floor does not go lower regardless of which features you use.
Can I use scroll-driven CSS animations in Next.js App Router today?
Yes, with a progressive enhancement caveat. Chrome and Edge have full support. Firefox support landed in version 110. Safari support as of mid-2026 is partial the basic scroll() timeline works but view() timeline support is still behind a flag in some versions. The safe approach is to define the animation as a CSS enhancement: elements look fine without it, and the animation is an additive improvement. Use @supports (animation-timeline: scroll()) to scope the animation to supporting browsers.
What is the difference between Motion and Framer Motion now?
They share the same maintainer and much of the same API surface, but Motion is the lightweight WAAPI-based engine and Framer Motion is the full-featured React integration. Motion is published as the motion package with a motion/react entry point. Framer Motion is the framer-motion package. You cannot use layout animations or AnimatePresence with the Motion package alone. If you need those features, you need framer-motion. If you do not, motion/react gives you almost everything else at a fraction of the size.
Do animations affect Core Web Vitals scores?
Yes, in two ways. First, JavaScript-driven animations that run on the main thread can block interaction processing and increase INP scores. Compositor-thread animations CSS transitions, keyframes, WAAPI on composited properties, scroll-driven CSS do not. Second, loading a large animation library adds to the JavaScript parse and execution time during initial load, which can delay Time to Interactive and indirectly affect your overall performance budget. Both effects are real and measurable in Chrome DevTools and Lighthouse, and both favor CSS-native or WAAPI-based animations over main-thread JavaScript animation for performance-sensitive pages.
Continue Reading
View All HubLevel Up Your Workflow
Free professional tools mentioned in this article
JWT Secret Key Generator
Generate cryptographically secure, high-entropy JWT secret keys instantly. A free, client-side CSPRNG key generator for secure HS256 and HS512 tokens.
Unix Timestamp Converter
Convert Unix timestamps to readable dates and back instantly. View the current epoch time, convert any timestamp, and see results in any timezone.
Advanced SEO Meta Tag & Open Graph Generator
Generate highly optimized meta tags, Twitter Cards, and Open Graph data for Google and Facebook with real-time visual previews.
Fancy Font & Stylish Text Generator
Transform your text into 50+ stylish and aesthetic fonts instantly. Perfect for Instagram bios, TikTok captions, and PUBG nicknames. One-click copy & paste.




