Framer Motion
Learn Framer Motion for creating smooth animations and transitions in React applications. This is a foundational concept in component-based UI development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world React experience. Take your time with each section and practice the examples
What is Framer Motion?
Framer Motion is a production-ready motion library for React. It provides a simple API for creating animations, gestures, and drag interactions.. This is an essential concept that every React developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Basic Animations
// Install Framer Motion
npm install framer-motion
// Basic animations
import { motion } from 'framer-motion';
function BasicAnimations() {
return (
<div>
{/* Fade in animation */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
<h1>Welcome to our app!</h1>
</motion.div>
{/* Slide in from left */}
<motion.div
initial={{ x: -100, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{ duration: 0.8, ease: "easeOut" }}
>
<p>This content slides in from the left</p>
</motion.div>
{/* Scale animation */}
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click me!
</motion.button>
{/* Staggered animations */}
<motion.ul
initial="hidden"
animate="visible"
variants={{
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1
}
}
}}
>
{['Item 1', 'Item 2', 'Item 3', 'Item 4'].map((item, index) => (
<motion.li
key={index}
variants={{
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
}}
>
{item}
</motion.li>
))}
</motion.ul>
</div>
);
}
// Animated card component
function AnimatedCard({ children }) {
return (
<motion.div
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
whileHover={{
y: -10,
boxShadow: "0 20px 40px rgba(0,0,0,0.1)"
}}
transition={{
duration: 0.3,
ease: "easeOut"
}}
style={{
padding: '20px',
border: '1px solid #ddd',
borderRadius: '8px',
backgroundColor: 'white'
}}
>
{children}
</motion.div>
);
}
// Usage
function CardGrid() {
const cards = [
{ id: 1, title: 'Card 1', content: 'This is the first card' },
{ id: 2, title: 'Card 2', content: 'This is the second card' },
{ id: 3, title: 'Card 3', content: 'This is the third card' },
];
return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '20px' }}>
{cards.map((card, index) => (
<AnimatedCard key={card.id}>
<h3>{card.title}</h3>
<p>{card.content}</p>
</AnimatedCard>
))}
</div>
);
}Advanced Animations
// Advanced Framer Motion features
import { motion, AnimatePresence } from 'framer-motion';
// Page transitions
function PageTransition({ children }) {
return (
<motion.div
initial={{ opacity: 0, x: 100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -100 }}
transition={{ duration: 0.5 }}
>
{children}
</motion.div>
);
}
// Modal with backdrop
function AnimatedModal({ isOpen, onClose, children }) {
return (
<AnimatePresence>
{isOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
zIndex: 1000,
}}
/>
<motion.div
initial={{ opacity: 0, scale: 0.8, y: 50 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8, y: 50 }}
transition={{ type: "spring", damping: 25, stiffness: 300 }}
style={{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
backgroundColor: 'white',
padding: '20px',
borderRadius: '8px',
zIndex: 1001,
minWidth: '300px',
}}
>
{children}
</motion.div>
</>
)}
</AnimatePresence>
);
}
// Drag and drop
function DraggableItem({ id, children }) {
return (
<motion.div
drag
dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
dragElastic={0.1}
whileDrag={{ scale: 1.1, boxShadow: "0 10px 20px rgba(0,0,0,0.2)" }}
style={{
padding: '10px',
border: '1px solid #ddd',
borderRadius: '4px',
backgroundColor: 'white',
cursor: 'grab',
}}
>
{children}
</motion.div>
);
}
// Gesture animations
function GestureExample() {
return (
<motion.div
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
drag="x"
dragConstraints={{ left: -100, right: 100 }}
dragElastic={0.2}
onDragEnd={(event, info) => {
console.log('Drag ended:', info);
}}
style={{
width: '100px',
height: '100px',
backgroundColor: '#ff6b6b',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
cursor: 'grab',
}}
>
Drag me!
</motion.div>
);
}
// Layout animations
function LayoutAnimation() {
const [items, setItems] = useState([1, 2, 3, 4, 5]);
const addItem = () => {
setItems([...items, items.length + 1]);
};
const removeItem = (index) => {
setItems(items.filter((_, i) => i !== index));
};
return (
<div>
<button onClick={addItem}>Add Item</button>
<motion.div layout>
{items.map((item, index) => (
<motion.div
key={item}
layout
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ duration: 0.3 }}
style={{
padding: '10px',
margin: '5px',
backgroundColor: '#f0f0f0',
borderRadius: '4px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<span>Item {item}</span>
<button onClick={() => removeItem(index)}>Remove</button>
</motion.div>
))}
</motion.div>
</div>
);
}
// Scroll-triggered animations
function ScrollAnimation() {
return (
<motion.div
initial={{ opacity: 0, y: 100 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.8 }}
style={{
padding: '40px',
backgroundColor: '#f8f9fa',
margin: '20px 0',
borderRadius: '8px',
}}
>
<h2>This animates when scrolled into view</h2>
<p>This content will animate when it comes into the viewport.</p>
</motion.div>
);
}