Framer Motion
Learn Framer Motion for creating smooth animations and transitions in React applications
85 min•By Priygop Team•Last updated: Feb 2026
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.
Basic Animations
Example
// 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
Example
// 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>
);
}