Command Palette

Search for a command to run...

UI Animation in 2025: Principles, Patterns, and Performance

UI Animation in 2025: Principles, Patterns, and Performance

Make motion do real UX work: principles, durations, easing, accessibility, and production-ready Next.js examples with CSS and Framer Motion.

3 min read·Web Design

Motion should clarify, not decorate. This guide covers principles, durations, easing, accessibility, and production patterns for Next.js with both CSS and Framer Motion.

Related: Web Design Best Practices · Web Application Design · UI Libraries


Principles

  • Purposeful: communicate state change (open/close, success, progress).
  • Brief: 150–240ms for small UI, 300–400ms for overlays.
  • Directional: motion should match spatial model (slide from source).
  • Consistent: same components, same durations and easings.
  • Respectful: honor prefers-reduced-motion with non-animated fallbacks.

Easing Recipes (feel right)

  • Entrance: cubic-bezier(0.2, 0.8, 0.2, 1) (easeOut-ish)
  • Exit: cubic-bezier(0.4, 0.0, 1, 1) (easeIn-ish)
  • Emphasis: Spring with low stiffness, high damping
:root {
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --dur-1: 160ms;
  --dur-2: 220ms;
  --dur-3: 320ms;
}

CSS-Only Patterns (fast, simple)

.modal-enter {
  opacity: 0;
  transform: translateY(8px);
}
.modal-enter-active {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-2) var(--ease-out);
}
.modal-exit {
  opacity: 1;
  transform: translateY(0);
}
.modal-exit-active {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--dur-2) var(--ease-in),
    transform var(--dur-2) var(--ease-in);
}

Reduced motion

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

Framer Motion (App Router)

"use client";
import { motion, AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";
 
export function RouteTransition({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();
  return (
    <AnimatePresence mode="wait">
      <motion.div
        key={pathname}
        initial={{ opacity: 0, y: 8 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0, y: 8 }}
        transition={{ duration: 0.22, ease: [0.2, 0.8, 0.2, 1] }}
      >
        {children}
      </motion.div>
    </AnimatePresence>
  );
}

Micro-interactions

"use client";
import { motion } from "framer-motion";
 
export function TapButton({ children }) {
  return (
    <motion.button
      whileTap={{ scale: 0.96 }}
      whileHover={{ y: -1 }}
      transition={{ type: "spring", stiffness: 500, damping: 40 }}
      className="rounded-md bg-neutral-900 px-4 py-2 text-white"
    >
      {children}
    </motion.button>
  );
}

Performance Guardrails

  • Animate transform/opacity; avoid width/height/top/left.
  • Avoid animating large shadows or blurs.
  • Use will-change: transform sparingly for complex elements.
  • Limit concurrent animations; stagger for readability.
  • Consider motion-safe loading (skeletons, progressive disclosure).

Testing & Accessibility

  • Verify keyboard + screen reader behavior doesn’t regress during motion.
  • Stop non-essential animations if tab is unfocused.
  • Provide “Turn off animations” in app settings if motion is a core theme.

Checklist

  • Motion clarifies intent
  • Durations & easings consistent
  • Reduced motion supported
  • No layout thrash
  • Measured in the field (INP/paint timings)

Keep exploring: Web Design Best Practices · Web Application Design · UI Libraries

Read more like this

UI Animation in 2025: Principles, Patterns, and Performance | Ruixen UI