Framer Motion Guide
Master the art of animations in React with Framer Motion.
Getting Started
Install Framer Motion:
npm install framer-motionBasic import and usage:
import { motion } from 'framer-motion';
function App() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
Hello Framer Motion!
</motion.div>
);
}AnimatePresence
Use AnimatePresence for exit animations and conditional rendering:
import { AnimatePresence, motion } from 'framer-motion';
function App() {
const [isVisible, setIsVisible] = useState(true);
return (
<AnimatePresence>
{isVisible && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.5 }}
>
I can fade in and out!
</motion.div>
)}
</AnimatePresence>
);
}Basic Animations
The three main props for animations are initial, animate, and exit:
import { motion } from 'framer-motion';
function Box() {
return (
<motion.div
initial={{ opacity: 0, scale: 0.5 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.5 }}
transition={{ duration: 0.5, ease: "easeOut" }}
>
I fade and scale in!
</motion.div>
);
}Variants
Define reusable animations with variants for cleaner code:
const boxVariants = {
hidden: {
opacity: 0,
scale: 0.5,
y: 25
},
visible: {
opacity: 1,
scale: 1,
y: 0,
transition: {
duration: 0.6,
ease: "easeOut"
}
},
exit: {
opacity: 0,
scale: 0.5,
transition: {
duration: 0.3
}
}
};
function AnimatedBox() {
return (
<motion.div
variants={boxVariants}
initial="hidden"
animate="visible"
exit="exit"
>
Using variants for cleaner code!
</motion.div>
);
}Stagger Animations
Create beautiful cascade effects with staggered animations:
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.2
}
}
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1 , y: 0, filter: "blur(0px)" }
};
function StaggeredList() {
const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
return (
<motion.ul
variants={containerVariants}
initial="hidden"
animate="visible"
>
{items.map((item, index) => (
<motion.li
key={index}
variants={itemVariants}
>
{item}
</motion.li>
))}
</motion.ul>
);
}Hover and Tap Animations
Add interactive animations with whileHover and whileTap:
function InteractiveButton() {
return (
<motion.button
whileHover={{
scale: 1.05,
boxShadow: "0 10px 25px rgba(0,0,0,0.15)"
}}
whileTap={{ scale: 0.95 }}
transition={{
type: "spring",
stiffness: 400,
damping: 10
}}
className="px-6 py-3 bg-blue-500 text-white rounded-lg"
>
Click me!
</motion.button>
);
}Advanced Animations
Spring animations for more natural movement:
const springConfig = {
type: "spring",
stiffness: 300,
damping: 30
};
function SpringBox() {
return (
<motion.div
initial={{ x: -100 }}
animate={{ x: 0 }}
transition={springConfig}
>
Natural spring movement!
</motion.div>
);
}Keyframe Animations
Create complex animations with arrays (keyframes):
function PulsingCircle() {
return (
<motion.div
animate={{
scale: [1, 1.2, 1],
backgroundColor: ["#ff0000", "#00ff00", "#0000ff", "#ff0000"]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
className="w-20 h-20 rounded-full"
/>
);
}Layout Animations
Smooth layout changes with the layout prop:
function LayoutExample() {
const [isExpanded, setIsExpanded] = useState(false);
return (
<motion.div
layout
onClick={() => setIsExpanded(!isExpanded)}
className={`cursor-pointer bg-blue-500 text-white p-4 rounded-lg ${isExpanded ? 'w-80 h-40' : 'w-40 h-20'}`}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
>
Click to expand!
</motion.div>
);
}Scroll-Triggered Animations
Use useInView hook for scroll-based animations:
import { useInView } from 'framer-motion';
import { useRef } from 'react';
function ScrollTriggered() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return (
<motion.div
ref={ref}
initial={{ opacity: 0 , y: 25, filter: "blur(10px)" }}
animate={isInView ? { opacity: 1 , y: 0, filter: "blur(0px)" } : {}}
transition={{ duration: 0.6, ease: "easeOut" }}
>
I animate when scrolled into view!
</motion.div>
);
}Best Practices
- Performance: Use
transformproperties (x, y, scale, rotate) for better performance - Accessibility: Respect
prefers-reduced-motionmedia query - Variants: Use variants for complex animations and better organization
- Springs: Prefer spring animations over duration-based for more natural feel
// Respect user preferences
const shouldReduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const variants = {
hidden: { opacity: 0, y: shouldReduceMotion ? 0 : 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: shouldReduceMotion ? 0 : 0.6
}
}
};Common Patterns
Here are some popular animation patterns you can use:
// Fade in up
const fadeInUp = {
initial: { opacity: 0, y: 60 },
animate: { opacity: 1 , y: 0, filter: "blur(0px)" },
transition: { duration: 0.6, ease: "easeOut" }
};
// Scale in
const scaleIn = {
initial: { scale: 0, opacity: 0 },
animate: { scale: 1, opacity: 1 },
transition: { duration: 0.5, ease: "backOut" }
};
// Slide in from left
const slideInLeft = {
initial: { x: -100, opacity: 0 },
animate: { x: 0, opacity: 1 },
transition: { duration: 0.6, ease: "easeOut" }
};Framer Motion provides a powerful and intuitive API for creating smooth, performant animations in React. Start with simple animations and gradually explore more advanced features as you become comfortable with the library.