Motion Animation Guide
Master modern web animations with Motion (formerly Framer Motion)
What is Motion?
Motion (formerly Framer Motion) is a production-ready animation library for React that makes creating smooth, performant animations simple and declarative. It's now open source and actively maintained by the Motion Division team.
Declarative
Simple, readable animation syntax
Performant
GPU-accelerated by default
Powerful
Advanced physics and gestures
Getting Started
Installation
# Using npm
npm install framer-motion
# Using pnpm
pnpm add framer-motion
# Using yarn
yarn add framer-motionBasic Usage
The simplest way to animate is using the motion component withinitial, animate, and transition props.
import { motion } from "framer-motion";
function App() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
<h1>Hello Motion!</h1>
</motion.div>
);
}I fade in when the page loads!
Using Variants
Variants allow you to define animation states that can be reused across components and orchestrated with stagger effects.
import { motion } from "framer-motion";
const containerVariants = {
hidden: { opacity: 0, scale: 0.8 },
visible: {
opacity: 1,
scale: 1,
transition: {
duration: 0.5,
when: "beforeChildren",
staggerChildren: 0.1
}
}
};
const itemVariants = {
hidden: { y: 20, opacity: 0 },
visible: { y: 0, opacity: 1 }
};
function AnimatedList() {
return (
<motion.ul
variants={containerVariants}
initial="hidden"
animate="visible"
>
{items.map(item => (
<motion.li key={item.id} variants={itemVariants}>
{item.text}
</motion.li>
))}
</motion.ul>
);
}Scroll-Triggered Animations
Scroll animations create engaging experiences by responding to user scrolling. Motion provides powerful hooks like useScroll and whileInViewto create scroll-based animations easily.
import { motion } from "framer-motion";
function FadeInOnScroll() {
return (
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
>
<h2>I fade in when scrolled into view!</h2>
</motion.div>
);
}Scroll to see me transform!
Opacity and scale change based on scroll position
import { motion, useScroll, useTransform } from "framer-motion";
function ParallaxElement() {
const { scrollYProgress } = useScroll();
const y = useTransform(scrollYProgress, [0, 1], [0, -100]);
return (
<motion.div style={{ y }}>
<h2>I move at a different rate than the scroll!</h2>
</motion.div>
);
}The bar above grows as you scroll down the page
import { motion, useScroll } from "framer-motion";
function ScrollProgress() {
const { scrollYProgress } = useScroll();
return (
<motion.div
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
height: "5px",
background: "linear-gradient(to right, #61dafb, #4caf50)",
scaleX: scrollYProgress,
transformOrigin: "0%"
}}
/>
);
}Gesture Animations
Motion makes it easy to add interactive gestures like hover, tap, and drag with simple props. These create engaging, responsive user experiences.
Hover over me! 🎨
import { motion } from "framer-motion";
function HoverCard() {
return (
<motion.div
whileHover={{
scale: 1.05,
boxShadow: "0 10px 30px rgba(0,0,0,0.3)"
}}
transition={{ type: "spring", stiffness: 300 }}
>
<h3>Hover over me!</h3>
</motion.div>
);
}import { motion } from "framer-motion";
function TapButton() {
return (
<motion.button
whileTap={{ scale: 0.95 }}
whileHover={{ scale: 1.05 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click Me!
</motion.button>
);
}Try dragging the box - it bounces back within constraints
import { motion } from "framer-motion";
function DraggableBox() {
return (
<motion.div
drag
dragConstraints={{ left: -100, right: 100, top: -100, bottom: 100 }}
dragElastic={0.2}
whileDrag={{ scale: 1.1, cursor: "grabbing" }}
>
Drag me around!
</motion.div>
);
}Layout & Exit Animations
AnimatePresence enables exit animations and layout prop automatically animates layout changes. Perfect for modals, lists, and dynamic UIs.
import { motion, AnimatePresence } from "framer-motion";
function Modal({ isOpen, onClose }) {
return (
<AnimatePresence>
{isOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="backdrop"
onClick={onClose}
/>
<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 }}
className="modal"
>
<h2>Modal Content</h2>
<button onClick={onClose}>Close</button>
</motion.div>
</>
)}
</AnimatePresence>
);
}Content for TAB1
This content smoothly transitions when switching tabs.
import { motion } from "framer-motion";
function Tabs() {
const [selected, setSelected] = useState("tab1");
return (
<div>
<div className="tabs">
{["tab1", "tab2", "tab3"].map((tab) => (
<button key={tab} onClick={() => setSelected(tab)}>
{tab}
{selected === tab && (
<motion.div
layoutId="activeTab"
className="activeIndicator"
/>
)}
</button>
))}
</div>
<AnimatePresence mode="wait">
<motion.div
key={selected}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
>
{/* Tab content */}
</motion.div>
</AnimatePresence>
</div>
);
}import { motion, AnimatePresence } from "framer-motion";
function AnimatedList({ items, onRemove }) {
return (
<AnimatePresence>
{items.map((item) => (
<motion.div
key={item.id}
layout
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ type: "spring", stiffness: 300, damping: 25 }}
>
{item.content}
<button onClick={() => onRemove(item.id)}>Remove</button>
</motion.div>
))}
</AnimatePresence>
);
}Spring Physics Playground
Spring animations feel more natural than traditional easing curves. Experiment with the physics parameters to understand how they affect motion.
Presets:
How quickly the spring tries to reach its target
How much resistance slows down the spring
The weight of the animated element
Preview:
import { motion } from "framer-motion";
function SpringAnimation() {
return (
<motion.div
initial={{ rotateY: 0 }}
animate={{ rotateY: 360 }}
transition={{
type: "spring",
stiffness: 90,
damping: 7,
mass: 0.75
}}
>
Animated Element
</motion.div>
);
}Understanding Spring Physics
🎯 Stiffness
Controls how forcefully the spring moves toward its target. Higher values create faster, more energetic animations. Lower values result in slower, more gradual motion.
Range: 1-400 (typical: 100-300)
🛑 Damping
Determines how quickly the spring settles. Higher damping reduces oscillation and makes the animation settle faster. Lower values create more bounce.
Range: 1-50 (typical: 10-30)
⚖️ Mass
Represents the weight or inertia of the element. Heavier objects (higher mass) take longer to accelerate and decelerate, creating a sense of physical presence.
Range: 0.1-5 (typical: 0.5-2)
Resources & Further Learning
Official Documentation
Tutorials & Guides
Best Practices
layout prop for automatic layout animationsprefers-reduced-motion for accessibilityAnimatePresence for exit animations