Claude Code for Framer Motion: React Animations and Transitions — Claude Skills 360 Blog
Blog / Frontend / Claude Code for Framer Motion: React Animations and Transitions
Frontend

Claude Code for Framer Motion: React Animations and Transitions

Published: March 12, 2027
Read time: 8 min read
By: Claude Skills 360

Framer Motion animates React components with declarative motion.* components — <motion.div animate={{ x: 100, opacity: 1 }} /> smoothly interpolates to the target values. Variants define reusable animation states: initial, animate, exit. AnimatePresence animates components when they’re removed from the React tree. Layout animations with layout prop measure and animate DOM position changes; layoutId creates shared element transitions between screens. useSpring produces physics-based animations from state; useScroll + useTransform builds scroll-driven effects. whileHover, whileTap, and whileDrag add gesture animations. staggerChildren in variants orchestrates sequential child animations. useAnimate imperatively controls animations for complex sequences. Claude Code generates Framer Motion animation configurations, variant definitions, gesture handlers, layout transition setups, and scroll-driven animation implementations.

CLAUDE.md for Framer Motion

## Framer Motion Stack
- Version: framer-motion >= 11.0
- Motion: <motion.div animate={{ opacity: 1, y: 0 }} initial={{ opacity: 0, y: 20 }} />
- Variants: variants={{ initial, animate, exit }} + staggerChildren for orchestration
- AnimatePresence: wrap mount/unmount to animate exit — mode="wait" for sequential
- Layout: layout prop on motion element — animates size/position changes
- LayoutId: layoutId="id" — shared element transition between renders
- Gestures: whileHover, whileTap, whileDrag — interactive spring animations
- Scroll: useScroll() + useTransform() for parallax and progress effects

Animation Variants

// components/animations/variants.ts — reusable animation variants
import type { Variants } from "framer-motion"

// Fade up — common page element entrance
export const fadeUpVariants: Variants = {
  initial: { opacity: 0, y: 20 },
  animate: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.4, ease: [0.16, 1, 0.3, 1] },
  },
  exit: { opacity: 0, y: -10, transition: { duration: 0.2 } },
}

// Stagger children — for lists
export const staggerContainerVariants: Variants = {
  initial: {},
  animate: {
    transition: {
      staggerChildren: 0.06,
      delayChildren: 0.1,
    },
  },
}

export const staggerItemVariants: Variants = {
  initial: { opacity: 0, y: 16 },
  animate: { opacity: 1, y: 0, transition: { duration: 0.4, ease: "easeOut" } },
}

// Scale pop — for cards, buttons
export const scaleVariants: Variants = {
  initial: { opacity: 0, scale: 0.92 },
  animate: { opacity: 1, scale: 1, transition: { type: "spring", stiffness: 400, damping: 30 } },
  exit: { opacity: 0, scale: 0.92, transition: { duration: 0.15 } },
}

// Slide in from right — for drawers, panels
export const slideInRightVariants: Variants = {
  initial: { x: "100%", opacity: 0 },
  animate: { x: 0, opacity: 1, transition: { type: "spring", damping: 30, stiffness: 300 } },
  exit: { x: "100%", opacity: 0, transition: { duration: 0.2, ease: "easeIn" } },
}

Animated Components

// components/animations/AnimatedOrderCard.tsx
import { motion } from "framer-motion"
import { staggerItemVariants } from "./variants"

export function AnimatedOrderCard({ order }: { order: Order }) {
  return (
    <motion.div
      variants={staggerItemVariants}
      layout  // Animate position changes (e.g., when filtering)
      whileHover={{
        scale: 1.01,
        boxShadow: "0 8px 30px rgba(0,0,0,0.12)",
        transition: { duration: 0.2 },
      }}
      className="border rounded-xl p-4 bg-white cursor-pointer"
    >
      <div className="flex justify-between">
        <div>
          <p className="font-semibold">#{order.id.slice(-8)}</p>
          <p className="text-muted-foreground text-sm">{order.status}</p>
        </div>
        <p className="font-bold">${(order.totalCents / 100).toFixed(2)}</p>
      </div>
    </motion.div>
  )
}

// Staggered list
export function AnimatedOrdersList({ orders }: { orders: Order[] }) {
  return (
    <motion.ul
      variants={staggerContainerVariants}
      initial="initial"
      animate="animate"
      className="space-y-3"
    >
      <AnimatePresence mode="popLayout">
        {orders.map(order => (
          <motion.li key={order.id} layout exit={{ opacity: 0, scale: 0.9 }}>
            <AnimatedOrderCard order={order} />
          </motion.li>
        ))}
      </AnimatePresence>
    </motion.ul>
  )
}

AnimatePresence for Modal

// components/ui/AnimatedModal.tsx — animated mount/unmount
"use client"
import { motion, AnimatePresence } from "framer-motion"

interface AnimatedModalProps {
  isOpen: boolean
  onClose: () => void
  children: React.ReactNode
}

export function AnimatedModal({ isOpen, onClose, children }: AnimatedModalProps) {
  return (
    <AnimatePresence>
      {isOpen && (
        <>
          {/* Backdrop */}
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.2 }}
            className="fixed inset-0 bg-black/50 z-40"
            onClick={onClose}
          />

          {/* Modal panel */}
          <motion.div
            initial={{ opacity: 0, scale: 0.95, y: 8 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.95, y: 8 }}
            transition={{ type: "spring", damping: 30, stiffness: 400 }}
            className="fixed inset-x-4 top-[10%] z-50 mx-auto max-w-lg rounded-2xl bg-white p-6 shadow-2xl"
          >
            {children}
          </motion.div>
        </>
      )}
    </AnimatePresence>
  )
}

Layout Animation — Shared Element Transition

// components/orders/OrderTransition.tsx — shared element transitions
import { motion, AnimatePresence } from "framer-motion"
import { useState } from "react"

interface OrderSummary {
  id: string
  status: string
  totalCents: number
}

export function OrdersWithDetail({ orders }: { orders: OrderSummary[] }) {
  const [selectedId, setSelectedId] = useState<string | null>(null)
  const selected = orders.find(o => o.id === selectedId)

  return (
    <>
      <div className="grid grid-cols-2 gap-4">
        {orders.map(order => (
          <motion.div
            key={order.id}
            layoutId={`order-${order.id}`}
            onClick={() => setSelectedId(order.id)}
            className="border rounded-xl p-4 cursor-pointer"
          >
            <motion.h3 layoutId={`order-title-${order.id}`}>
              #{order.id.slice(-8)}
            </motion.h3>
            <p>${(order.totalCents / 100).toFixed(2)}</p>
          </motion.div>
        ))}
      </div>

      <AnimatePresence>
        {selected && (
          <>
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              className="fixed inset-0 bg-black/50 z-40"
              onClick={() => setSelectedId(null)}
            />

            <motion.div
              layoutId={`order-${selected.id}`}
              className="fixed inset-4 z-50 rounded-2xl bg-white p-8 overflow-auto"
            >
              <motion.h2 layoutId={`order-title-${selected.id}`} className="text-2xl font-bold">
                Order #{selected.id.slice(-8)}
              </motion.h2>
              <p>Status: {selected.status}</p>
              <p>Total: ${(selected.totalCents / 100).toFixed(2)}</p>
              <button onClick={() => setSelectedId(null)} className="mt-4">
                Close
              </button>
            </motion.div>
          </>
        )}
      </AnimatePresence>
    </>
  )
}

Scroll Animations

// components/landing/ScrollProgress.tsx — scroll-driven animations
"use client"
import { useRef } from "react"
import { motion, useScroll, useTransform, useSpring } from "framer-motion"

export function ScrollProgress() {
  const { scrollYProgress } = useScroll()
  const smoothProgress = useSpring(scrollYProgress, { stiffness: 100, damping: 30 })

  return (
    <motion.div
      className="fixed top-0 left-0 right-0 h-1 bg-primary z-50 origin-left"
      style={{ scaleX: smoothProgress }}
    />
  )
}

// Parallax section
export function ParallaxSection({ children }: { children: React.ReactNode }) {
  const ref = useRef<HTMLDivElement>(null)
  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ["start end", "end start"],
  })

  const y = useTransform(scrollYProgress, [0, 1], ["-15%", "15%"])
  const opacity = useTransform(scrollYProgress, [0, 0.2, 0.8, 1], [0, 1, 1, 0])

  return (
    <div ref={ref} className="overflow-hidden">
      <motion.div style={{ y, opacity }}>
        {children}
      </motion.div>
    </div>
  )
}

For the Motion One alternative (now motion/mini) that provides a smaller bundle for simpler animations where Framer Motion’s full feature set and Spring physics aren’t needed — CSS animation driving with a Web Animations API wrapper, see the CSS animation guide for lightweight motion. For the React Spring alternative that uses the same physics-based spring model as Framer Motion but with a hooks-first API (useSpring, useTrail, useChain) — older API but with more granular control over spring configurations, see the animation patterns guide. The Claude Skills 360 bundle includes Framer Motion skill sets covering variants, AnimatePresence, and scroll animations. Start with the free tier to try animation generation.

Keep Reading

Frontend

Claude Code for Chart.js Advanced: Custom Plugins and Mixed Charts

Advanced Chart.js patterns with Claude Code — chart.register() for tree-shaking, mixed chart types combining bar and line, custom plugin API with beforeDraw and afterDatasetsDraw hooks, ScriptableContext for computed colors, ChartDataLabels plugin for value labels, chartjs-plugin-zoom for pan and zoom, custom gradient fills via ctx.createLinearGradient, ChartJS annotation plugin for threshold lines, streaming data with chartjs-plugin-streaming, and react-chartjs-2 with useRef and chart instance.

6 min read Jun 27, 2027
Frontend

Claude Code for Nivo: Rich SVG and Canvas Charts

Build rich data visualizations with Nivo and Claude Code — ResponsiveLine and ResponsiveBar for adaptive charts, ResponsiveHeatMap for matrix data, ResponsiveTreeMap for hierarchal data, ResponsiveSunburst for nested proportions, ResponsiveChord for relationship diagrams, ResponsiveCalendar for activity heat maps, ResponsiveNetwork for force graphs, NivoTheme for consistent styling, tooltip customization with sliceTooltip, and motion config for spring animations.

6 min read Jun 26, 2027
Frontend

Claude Code for Victory Charts: React Native and Web Charts

Build cross-platform charts with Victory and Claude Code — VictoryChart, VictoryLine, VictoryBar, and VictoryScatter for web and React Native, VictoryPie for donut charts, VictoryArea for stacked areas, VictoryAxis for custom axes, VictoryTooltip and VictoryVoronoiContainer for hover tooltips, VictoryBrushContainer for range selection, VictoryZoomContainer for pan and zoom, VictoryLegend for series labels, custom theme with VictoryTheme, and VictoryStack for grouped bars.

6 min read Jun 25, 2027

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free