Animations in React can be achieved through CSS, JavaScript libraries, or React-specific animation frameworks. The best approach depends on complexity, performance needs, and maintainability.
1. CSS Transitions — simple state-based animations:
1import { useState } from "react";23function ToggleBox() {4 const [expanded, setExpanded] = useState(false);56 return (7 <div8 onClick={() => setExpanded(!expanded)}9 style={{10 width: expanded ? "200px" : "100px",11 height: expanded ? "200px" : "100px",12 backgroundColor: expanded ? "steelblue" : "lightgray",13 transition: "all 0.3s ease-in-out",14 cursor: "pointer",15 borderRadius: "8px",16 }}17 />18 );19}
2. CSS Keyframes — complex multi-step animations:
1// In your CSS file2// @keyframes slideIn {3// from { opacity: 0; transform: translateY(20px); }4// to { opacity: 1; transform: translateY(0); }5// }6// .slide-in {7// animation: slideIn 0.5s ease forwards;8// }910// In React11function AnimatedCard({ title }: { title: string }) {12 return (13 <div className="slide-in" style={{ padding: "16px", border: "1px solid #ccc" }}>14 <h3>{title}</h3>15 </div>16 );17}
3. Framer Motion — the most popular React animation library:
1import { motion, AnimatePresence } from "framer-motion";23function AnimatedList({ items }: { items: { id: number; text: string }[] }) {4 return (5 <AnimatePresence>6 {items.map(item => (7 <motion.div8 key={item.id}9 initial={{ opacity: 0, x: -50 }}10 animate={{ opacity: 1, x: 0 }}11 exit={{ opacity: 0, x: 50 }}12 transition={{ duration: 0.3, ease: "easeOut" }}13 layout14 >15 {item.text}16 </motion.div>17 ))}18 </AnimatePresence>19 );20}2122// Hover and tap animations23function AnimatedButton() {24 return (25 <motion.button26 whileHover={{ scale: 1.05 }}27 whileTap={{ scale: 0.95 }}28 initial={{ opacity: 0 }}29 animate={{ opacity: 1 }}30 >31 Click me32 </motion.button>33 );34}
4. React Spring — physics-based animations:
1import { useSpring, animated } from "@react-spring/web";23function FadeIn() {4 const props = useSpring({5 opacity: 1,6 from: { opacity: 0 },7 config: { duration: 1000 },8 });9 return <animated.div style={props}>Hello World</animated.div>;10}
Performance best practices:
transform and opacity for GPU-accelerated animationswidth, height, top, left, margin — they trigger layout recalculationswill-change CSS property sparingly (only for elements that will animate)prefers-reduced-motion media query for accessibility:1function usePrefersReducedMotion(): boolean {2 const [prefersReduced, setPrefersReduced] = useState(false);3 useEffect(() => {4 const mq = window.matchMedia("(prefers-reduced-motion: reduce)");5 setPrefersReduced(mq.matches);6 const handler = (e: MediaQueryListEvent) => setPrefersReduced(e.matches);7 mq.addEventListener("change", handler);8 return () => mq.removeEventListener("change", handler);9 }, []);10 return prefersReduced;11}
Choosing the right tool: