Framer Motion: Essential Animation Patterns
Framer Motion makes React animations simple and powerful. Here are the patterns you'll use most.
Setup
npm install framer-motion
Basic Animations
Fade In
import { motion } from 'framer-motion'
export function FadeIn({ children }) {
return { children }
}
Slide In
export function SlideIn({ children }) {
return { children }
}
Hover & Tap Interactions
export function AnimatedButton({ children, onClick }) {
return { children }
}
Variants (Staggered Animations)
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
}
const item = {
hidden: { opacity: 0, x: -20 },
show: { opacity: 1, x: 0 }
}
export function StaggeredList({ items }) {
return (
{items.map((text, i) => (
{text}
))}
)
}
Drag and Drop
export function DraggableCard() {
return (
)
}
Layout Animations
import { useState } from 'react'
export function ExpandableCard() {
const [isOpen, setIsOpen] = useState(false)
return (
<motion.div
layout
onClick={() => setIsOpen(!isOpen)}
className="bg-white p-6 rounded-lg cursor-pointer"
>
Title
{isOpen && (
Content appears here
)}
)
}
Scroll Animations
import { useScroll, useTransform } from 'framer-motion'
export function ParallaxSection({ children }) {
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], ['0%', '50%'])
return { children }
}
Scroll Progress Bar
export function ScrollProgress() {
const { scrollYProgress } = useScroll()
return (
)
}
Exit Animations
import { AnimatePresence } from 'framer-motion'
export function Modal({ isOpen, onClose, children }) {
return (
{isOpen && (
<>
{children}
</>
)}
)
}
Page Transitions
import { usePathname } from 'next/navigation'
const pageVariants = {
initial: { opacity: 0, x: -20 },
animate: { opacity: 1, x: 0 },
exit: { opacity: 0, x: 20 },
}
export function PageTransition({ children }) {
const pathname = usePathname()
return { children }
}
Like Button Microinteraction
export function LikeButton() {
const [liked, setLiked] = useState(false)
return (
<motion.button
onClick={() => setLiked(!liked)}
whileTap={{ scale: 0.9 }}
>
)
}
Performance Tips
- Use
transformandopacity- hardware accelerated - Avoid animating
width/height- usescaleinstead - Add
layoutsparingly - can be expensive - Respect
prefers-reduced-motion:
const shouldReduceMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)',
).matches
Learn More: Framer Motion Docs