Animating SVG Paths with CSS and Framer Motion
A comprehensive guide to animating SVG paths. Learn how to draw lines with CSS and create complex physics-based animations using Framer Motion in React.
Static SVGs are great for performance, but an animated SVG can tell a story, explain a concept, or provide visual delight that raster images simply cannot match.
There are two primary ways to animate SVGs on the modern web: CSS Keyframes (for simple, declarative animations) and JavaScript libraries like Framer Motion (for complex, interactive, or physics-based animations in React).
Here is how to master both.
Part 1: The Classic CSS “Line Draw” Effect
The most famous SVG animation is the “line draw” effect, where an icon or illustration appears to be sketched onto the screen in real-time. This is achieved entirely with CSS using stroke-dasharray and stroke-dashoffset.
How it Works
stroke-dasharrayturns a solid line into a dashed line. If you set the dash length to be equal to the entire length of the path, you get one massive dash that covers the whole path.stroke-dashoffsetpushes the start of that dash backwards. If you offset it by the exact length of the path, the dash is pushed entirely out of view.- By animating the offset back to
0, the line “draws” itself.
<!-- An SVG Line -->
<svg viewBox="0 0 100 100">
<path id="myPath" d="M10 50 Q 50 10 90 50" fill="transparent" stroke="blue" stroke-width="2"/>
</svg>
#myPath {
/* Assuming the path's total length is roughly 150 */
stroke-dasharray: 150;
stroke-dashoffset: 150;
animation: draw 2s ease-in-out forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
The Catch: You need to know the exact length of the path. You can find this using JavaScript (document.getElementById('myPath').getTotalLength()).
Part 2: Supercharging SVG Animation with Framer Motion
While CSS is great for simple drawing effects, it struggles with complex staggering, physics-based springs, or interactive dragging. In the React ecosystem, Framer Motion is the gold standard for solving this.
Framer Motion has native support for animating SVGs via its motion.path, motion.circle, and motion.svg components.
Example 1: The Declarative Line Draw
Framer Motion completely eliminates the need to calculate getTotalLength(). You can simply animate the pathLength property from 0 to 1.
import { motion } from 'framer-motion';
export const AnimatedCheckmark = () => (
<svg viewBox="0 0 24 24" width="48" height="48">
<motion.path
d="M5 13l4 4L19 7"
fill="transparent"
stroke="#10B981"
strokeWidth="2"
initial={{ pathLength: 0, opacity: 0 }}
animate={{ pathLength: 1, opacity: 1 }}
transition={{ duration: 0.5, ease: "easeOut" }}
/>
</svg>
);
Example 2: Staggered Path Animations
Imagine an icon composed of three distinct lines (like a hamburger menu). You want them to draw in sequence: Line 1, then Line 2, then Line 3.
Doing this in CSS requires calculating precise animation delays. In Framer Motion, you use variants and orchestration.
import { motion } from 'framer-motion';
const iconVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2, // Delay each child by 0.2s
},
},
};
const pathVariants = {
hidden: { pathLength: 0, opacity: 0 },
visible: { pathLength: 1, opacity: 1 },
};
export const MenuIcon = () => (
<motion.svg viewBox="0 0 24 24" initial="hidden" animate="visible" variants={iconVariants}>
<motion.line x1="4" y1="6" x2="20" y2="6" stroke="black" variants={pathVariants} />
<motion.line x1="4" y1="12" x2="20" y2="12" stroke="black" variants={pathVariants} />
<motion.line x1="4" y1="18" x2="20" y2="18" stroke="black" variants={pathVariants} />
</motion.svg>
);
Example 3: Physics-Based Scaling (The Spring)
Framer Motion excels at spring physics, which makes UI feel highly responsive and natural.
export const BouncingCircle = () => (
<motion.svg viewBox="0 0 100 100">
<motion.circle
cx="50"
cy="50"
r="40"
fill="#3B82F6"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{
type: "spring",
stiffness: 260,
damping: 20
}}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
/>
</motion.svg>
);
Summary
Use CSS animations for lightweight, non-interactive effects like continuous spinners or simple hover states. Switch to Framer Motion when you need complex path length drawing, sequence staggering, physics-based interactions, or when building entirely within a React application.