Framer Motion

Production-ready animation library for React and Next.js

✨ What is Framer Motion?

Framer Motion is a powerful animation library for React that makes it easy to create smooth, professional animations. It provides simple APIs for complex animations, gestures, and page transitions in Next.js applications.


# Install Framer Motion
npm install framer-motion

# Import and use in components
import { motion } from 'framer-motion'
                                    

Key Framer Motion Features

🎬

Animations

Smooth declarative animations

<motion.div
  animate={{ x: 100 }}
/>
👆

Gestures

Drag, hover, and tap interactions

<motion.div
  whileHover={{ scale: 1.1 }}
  whileTap={{ scale: 0.9 }}
/>
🔄

Transitions

Page and route transitions

<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
/>
🎯

Variants

Reusable animation states

const variants = {
  hidden: { opacity: 0 },
  visible: { opacity: 1 }
}

🔹 Basic Animation

Create simple animations by replacing HTML elements with motion components. The animate prop defines the final state, and Framer Motion automatically animates from the current state.

// components/FadeIn.js
'use client'
import { motion } from 'framer-motion'

export default function FadeIn() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
      className="p-6 bg-blue-500 text-white rounded-lg"
    >
      <h2>Hello, I fade in!</h2>
      <p>This component animates when it appears.</p>
    </motion.div>
  )
}

Animation Effect:

The div fades in from opacity 0 to 1 and moves up 20px over 0.5 seconds.

🔹 Hover and Tap Animations

Add interactive animations that respond to user actions. These gesture-based animations provide immediate feedback and make your interface feel more responsive and engaging.

// components/InteractiveButton.js
'use client'
import { motion } from 'framer-motion'

export default function InteractiveButton() {
  return (
    <motion.button
      whileHover={{ 
        scale: 1.05,
        boxShadow: "0px 5px 15px rgba(0, 0, 0, 0.2)"
      }}
      whileTap={{ scale: 0.95 }}
      transition={{ type: "spring", stiffness: 400, damping: 17 }}
      className="px-6 py-3 bg-purple-500 text-white rounded-lg"
    >
      Hover and Click Me!
    </motion.button>
  )
}

🔹 Variants for Complex Animations

Define animation states using variants for cleaner code and coordinated animations. Variants make it easy to orchestrate animations across multiple elements and create consistent motion patterns.

// components/AnimatedList.js
'use client'
import { motion } from 'framer-motion'

const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1
    }
  }
}

const itemVariants = {
  hidden: { opacity: 0, x: -20 },
  visible: { opacity: 1, x: 0 }
}

export default function AnimatedList() {
  const items = ['Item 1', 'Item 2', 'Item 3', 'Item 4']
  
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
      className="space-y-2"
    >
      {items.map((item, index) => (
        <motion.li
          key={index}
          variants={itemVariants}
          className="p-4 bg-gray-100 rounded"
        >
          {item}
        </motion.li>
      ))}
    </motion.ul>
  )
}

🔹 Drag Interactions

Enable drag functionality with simple props. Framer Motion handles all the complex physics and constraints, making it easy to create draggable elements with natural motion.

// components/DraggableBox.js
'use client'
import { motion } from 'framer-motion'

export default function DraggableBox() {
  return (
    <div className="h-64 bg-gray-100 rounded-lg relative">
      <motion.div
        drag
        dragConstraints={{
          top: 0,
          left: 0,
          right: 200,
          bottom: 200
        }}
        dragElastic={0.2}
        whileDrag={{ scale: 1.1 }}
        className="w-20 h-20 bg-blue-500 rounded-lg cursor-grab active:cursor-grabbing"
      >
        <p className="text-white text-center leading-20">Drag me!</p>
      </motion.div>
    </div>
  )
}

🔹 Page Transitions

Create smooth transitions between pages in your Next.js app. AnimatePresence allows components to animate out when they're removed from the React tree.

// app/layout.js
'use client'
import { AnimatePresence, motion } from 'framer-motion'
import { usePathname } from 'next/navigation'

export default function RootLayout({ children }) {
  const pathname = usePathname()
  
  return (
    <html lang="en">
      <body>
        <AnimatePresence mode="wait">
          <motion.div
            key={pathname}
            initial={{ opacity: 0, x: 20 }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: -20 }}
            transition={{ duration: 0.3 }}
          >
            {children}
          </motion.div>
        </AnimatePresence>
      </body>
    </html>
  )
}

🔹 Scroll Animations

Trigger animations based on scroll position using useScroll and useTransform hooks. Create parallax effects, progress bars, and elements that animate as users scroll.

// components/ScrollReveal.js
'use client'
import { motion, useScroll, useTransform } from 'framer-motion'
import { useRef } from 'react'

export default function ScrollReveal() {
  const ref = useRef(null)
  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ["start end", "end start"]
  })
  
  const opacity = useTransform(scrollYProgress, [0, 0.5, 1], [0, 1, 0])
  const scale = useTransform(scrollYProgress, [0, 0.5, 1], [0.8, 1, 0.8])
  
  return (
    <motion.div
      ref={ref}
      style={{ opacity, scale }}
      className="p-8 bg-gradient-to-r from-purple-500 to-pink-500 text-white rounded-lg"
    >
      <h2 className="text-2xl font-bold">Scroll to reveal!</h2>
      <p>This element animates as you scroll.</p>
    </motion.div>
  )
}

🔹 Keyframe Animations

Create complex multi-step animations using arrays of values. Keyframes allow you to define multiple animation states that play in sequence.

// components/BouncingBall.js
'use client'
import { motion } from 'framer-motion'

export default function BouncingBall() {
  return (
    <motion.div
      animate={{
        y: [0, -100, 0],
        scale: [1, 1.2, 1],
        rotate: [0, 180, 360]
      }}
      transition={{
        duration: 2,
        repeat: Infinity,
        ease: "easeInOut"
      }}
      className="w-16 h-16 bg-red-500 rounded-full"
    />
  )
}

🔹 Layout Animations

Automatically animate layout changes with the layout prop. Framer Motion smoothly transitions between different layouts, sizes, and positions without manual calculations.

// components/ExpandableCard.js
'use client'
import { motion } from 'framer-motion'
import { useState } from 'react'

export default function ExpandableCard() {
  const [isExpanded, setIsExpanded] = useState(false)
  
  return (
    <motion.div
      layout
      onClick={() => setIsExpanded(!isExpanded)}
      className="p-6 bg-white rounded-lg shadow-lg cursor-pointer"
      style={{ width: isExpanded ? '400px' : '200px' }}
    >
      <motion.h2 layout className="text-xl font-bold">
        Click to expand
      </motion.h2>
      {isExpanded && (
        <motion.p
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          className="mt-4"
        >
          This content appears when expanded!
        </motion.p>
      )}
    </motion.div>
  )
}

🧠 Test Your Knowledge

Which prop is used to enable drag functionality in Framer Motion?