Animated Icons in React: 5 Ways to Add Them (CSS, SVG, Motion, Lottie, Rive)
TL;DR
- Five ways to animate icons in React: CSS transitions, animated SVG, Motion, Lottie and Rive
- CSS covers hover lifts and spins; Motion handles icon swaps with springs; Lottie plays designer timelines
- Rive is the strongest choice for interactive icons (hover, toggles, reactions) because the state machine lives in the file
- Ready-made, accessible animated icons are in the animated icons collection
Animated icons are one of the cheapest ways to make a React app feel finished. A bell that rings, a heart that pops, a search icon that bounces when you hover it: each one tells people the interface is alive and listening. This guide covers the five practical ways to add animated icons to a React or Next.js app, with code for each, and when to pick which.
If you would rather skip straight to working components, the animated icons collection has live, accessible icons you can add with one prompt.
1. CSS transitions on an icon component
The lightest option. Any icon component that renders an <svg> (Lucide, Heroicons, your own) can be animated with a transition on transform.
// HoverIcon.tsx
export function HoverIcon({ children, label }: { children: React.ReactNode; label: string }) {
return (
<button aria-label={label} className="icon-button">
{children}
</button>
)
}.icon-button svg {
transition: transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.icon-button:hover svg,
.icon-button:focus-visible svg {
transform: scale(1.15) rotate(-8deg);
}
@media (prefers-reduced-motion: reduce) {
.icon-button svg { transition: none; }
}The cubic-bezier(0.34, 1.56, 0.64, 1) curve overshoots slightly, which gives a springy feel without a JavaScript library. Use it for hover lifts, spins and colour changes. For eight ready-made effects, see icon hover animation with CSS.
2. Animated SVG (stroke drawing and morphing)
Line icons can be drawn on with stroke-dasharray and stroke-dashoffset. This is how "self-drawing" checkmarks and loaders work.
.check path {
stroke-dasharray: 24;
stroke-dashoffset: 24;
transition: stroke-dashoffset 400ms ease-out;
}
.done .check path {
stroke-dashoffset: 0;
}Set pathLength="24" on the <path> so the dash length does not depend on the real path length. The animated SVG icons guide covers drawing, morphing and transform-origin pitfalls in detail.
3. Motion (Framer Motion) for state changes
When an icon changes state (play to pause, menu to close, muted to unmuted) you want spring physics and exit animations. Motion handles both.
import { AnimatePresence, motion } from 'framer-motion'
import { Volume2, VolumeX } from 'lucide-react'
export function MuteButton({ muted, onToggle }: { muted: boolean; onToggle: () => void }) {
return (
<button aria-label="Sound" aria-pressed={!muted} onClick={onToggle}>
<AnimatePresence mode="wait" initial={false}>
<motion.span
key={muted ? 'off' : 'on'}
initial={{ scale: 0.6, rotate: -20, opacity: 0 }}
animate={{ scale: 1, rotate: 0, opacity: 1 }}
exit={{ scale: 0.6, rotate: 20, opacity: 0 }}
transition={{ type: 'spring', stiffness: 500, damping: 25 }}
style={{ display: 'inline-flex' }}
>
{muted ? <VolumeX /> : <Volume2 />}
</motion.span>
</AnimatePresence>
</button>
)
}This swaps two static icons with a spring. It is quick to build, but the icon itself never changes shape. For that you need a timeline or a state machine.
4. Lottie for designer-made timelines
Lottie plays animations exported from After Effects as JSON. It is a good fit when a designer has already animated the icon and you only need to play it.
import Lottie from 'lottie-react'
import bell from './bell.json'
export function LottieBell() {
return <Lottie animationData={bell} loop={false} style={{ width: 48 }} />
}Lottie is mostly play, pause and seek. Hover states, toggles and multiple states need extra code that scrubs between frames, and each file is often 10 to 100 KB of JSON.
5. Rive for interactive icons
Rive files carry their own state machine: hover, click and toggle logic live inside the animation, and your code sets inputs. That makes Rive the strongest option for icons that react to people, such as nav icons, toggles and reactions.
import { useRive, useStateMachineInput } from '@rive-app/react-canvas'
export function RiveBell() {
const { rive, RiveComponent } = useRive({
src: '/mute-bell.riv',
stateMachines: 'State Machine 1',
autoplay: true,
})
const toggle = useStateMachineInput(rive, 'State Machine 1', 'Trigger 1')
return (
<button aria-label="Notifications" onClick={() => toggle?.fire()} style={{ width: 96, height: 96 }}>
<RiveComponent />
</button>
)
}Rive icon files are small (the icons in our collection range from 3 KB to 60 KB) and the free Rive editor lets you change colours, shapes and timing without touching code. The trade-off is framing: artboards often include padding and backgrounds, so you need to crop and size the canvas. Our Mute Bell Toggle prompt handles that, plus keeping the button's state in sync with what the animation shows.
Which one should you use?
| Need | Use |
|---|---|
| Hover lift, spin or colour change | CSS transitions |
| Line icon drawing itself | Animated SVG |
| Swapping icons with a spring | Motion |
| Playing a designer's After Effects animation | Lottie |
| Hover, toggle or multi-state icons | Rive |
For a deeper comparison of file size and workflow, read Lottie vs Rive vs CSS for animated icons.
Make animated icons accessible
<button> elements with an aria-label.aria-pressed, and keep that value in sync with the animation.:focus-visible in CSS, onFocus in React).prefers-reduced-motion by shortening or removing motion.Skip the wiring
Every icon in the animated icons collection is a complete React component: framed, accessible, with keyboard support and a guide to customising both the code and the artwork. Paste the prompt into Cursor, Claude Code, Lovable or v0 and the agent installs it in one pass.
More articles
Animated SVG Icons: How to Make Icons Move (Draw, Morph, Transform)
How to make animated SVG icons: stroke drawing with pathLength, transforms with transform-box, path morphing, hover triggers and React components, plus the mistakes that break them.
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.
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.