TL;DR
- Three techniques cover most animated SVG icons: stroke drawing, transforms on parts, and path morphing
- pathLength="1" makes stroke drawing work without measuring paths
- transform-box: fill-box fixes rotations that swing around the wrong point
- Interactive, multi-state icons are in the animated icons collection
Animated SVG icons are icons that move using nothing but SVG and CSS: a checkmark that draws itself, a menu that morphs into a close button, a loader that traces a circle. They are tiny, crisp at any size, and need no runtime. This guide shows how to make SVG icons move, the three techniques that cover almost every case, and the mistakes that make them jump or blur.
Why animate icons as SVG?
The limit is complexity. SVG plus CSS is excellent for line drawing, transforms and simple morphs, and awkward for character animation or multi-state logic. For those, see the comparison in Lottie vs Rive vs CSS for animated icons.
Technique 1: stroke drawing
Line icons can draw themselves. The trick is a dashed stroke with one dash as long as the path, offset by its full length, then animated to zero.
<svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path class="draw" pathLength="1" d="M5 13l4 4L19 7" />
</svg>.draw {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: draw 600ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }pathLength="1" normalises the path, so 1 is always "the whole path" and you never need to measure it with getTotalLength(). Stagger several paths with animation-delay to draw an icon stroke by stroke.
Technique 2: transforms on parts of the icon
Give each part of the icon its own group and animate it separately: a bell's clapper, an envelope's flap, the hands of a clock.
<svg viewBox="0 0 24 24" width="32" height="32" aria-hidden="true">
<g class="lid"><path d="M4 8h16" /></g>
<path d="M6 8l1 12h10l1-12" />
</svg>.lid {
transform-box: fill-box;
transform-origin: 0% 100%;
transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
button:hover .lid { transform: rotate(-25deg) translateY(-2px); }transform-box: fill-box makes transform-origin relative to the part itself instead of the whole SVG canvas. Without it, rotations swing around the top-left corner of the icon, which is the most common reason SVG icon animations look broken.
Technique 3: morphing between shapes
You can animate the d attribute between two paths with the same number and type of points. Chromium browsers and Firefox animate d in CSS (Safari does not yet, and simply jumps to the end shape):
.menu-line {
d: path("M4 12h16");
transition: d 300ms ease;
}
.open .menu-line { d: path("M6 6l12 12"); }For the classic hamburger-to-close morph, animating three separate lines with transforms works in every browser, so prefer it over path morphing when Safari matters.
Making SVG icons move on hover
Trigger icon animations from the interactive element, and include keyboard focus:
.icon-button:hover .draw,
.icon-button:focus-visible .draw { animation: draw 500ms ease-out; }More ready-made hover effects (ring, wiggle, bounce, spin) are in icon hover animation with CSS.
Animated SVG icons in React
Inline the SVG as a component so you can target its parts, and switch classes with state:
export function CheckIcon({ done }: { done: boolean }) {
return (
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" strokeWidth={2} aria-hidden="true">
<path className={done ? 'draw' : 'draw paused'} pathLength={1} d="M5 13l4 4L19 7" />
</svg>
)
}If you use Lucide, the icons already render inline SVG with stroke="currentColor", so every technique here applies. See how to animate Lucide icons in React.
Common mistakes
transform-box: fill-box and a transform-origin on the part you rotate.transform: scale() instead.@media (prefers-reduced-motion: no-preference).When to go beyond SVG
When an icon needs squash and stretch, several states, or a different move per icon, an interactive runtime such as Rive does the work for you. The animated icons collection has hover icons, animated nav icons, a mute toggle and emoji reactions, each a complete React component you add with one prompt.
More articles
Animated Icons in React: 5 Ways to Add Them (CSS, SVG, Motion, Lottie, Rive)
How to add animated icons to a React or Next.js app: CSS hover transitions, animated SVG, Motion, Lottie and Rive, with code for each and a guide to picking the right one.
Icon Hover Animation with CSS: 8 Effects with Copy-Paste Code
Eight CSS icon hover effects (spring scale, tilt, bell ring, wiggle, bounce, spin, stroke draw-on and colour sweep) with copy-paste code that stays smooth and accessible.
How to Animate Lucide Icons in React (Hover, Click and Loop)
Animate lucide-react icons with CSS and Motion: hover rings and tilts, stroke redraws, spring click feedback and reduced-motion-safe loops, without changing icon libraries.