SVG Animations with CSS & JavaScript: Code Examples for Developers (2026)
Practical code examples for SVG animation using CSS keyframes, GSAP, Framer Motion, and vanilla JavaScript. Copy-paste snippets for loaders, transitions, hover effects, and scroll-triggered animations.

Founder and developer of VectoSolve
Self-taught developer who founded VectoSolve in 2024. He builds the conversion engine and the cutting, embroidery and 3D printing exports, working with the VectoSolve team of graphic designers.
How this article was made: drafted with AI assistance, then edited and fact-checked before publication. About the author
Try it on your own file
Free preview, no signup. Drop an image and see the vector before deciding anything.
Key Takeaways
- CSS animations handle 80% of SVG animation needs with zero JavaScript and hardware-accelerated performance
- The Web Animations API provides native JavaScript control without external libraries
-
Always animate only
transformandopacityfor 60fps compositor-thread animations -
Use
prefers-reduced-motionmedia query to respect user accessibility preferences - GSAP remains the gold standard for complex SVG timeline animations in 2026
- AI-powered tools like Vectosolve can generate optimized SVG animations in seconds
Why SVG Animations Matter in 2026
SVG animations have become the backbone of modern web interfaces. From subtle micro-interactions that guide users through a checkout flow to full-screen hero animations that define a brand's identity, animated SVGs deliver resolution-independent, lightweight, and accessible motion that no other format can match.
Unlike raster-based animations (GIFs, animated PNGs, or even video), SVGs scale perfectly to any screen size, remain crisp on 4K and retina displays, and can be manipulated with the same CSS and JavaScript you already know. In 2026, with Core Web Vitals directly impacting search rankings and user experience expectations at an all-time high, mastering SVG animation isn't optional -- it's essential.
This guide walks you through every major approach to animating SVGs, from pure CSS to advanced JavaScript libraries, with production-ready code examples at each step.
CSS Animation Fundamentals for SVG
CSS is your first and often best tool for SVG animations. The browser's compositor thread handles CSS animations on transform and opacity properties without touching the main thread, giving you buttery-smooth 60fps performance for free.
CSS Transitions: The Simplest Approach
Transitions are perfect for state-based animations -- hover effects, focus states, and toggled classes. They interpolate between two states with minimal code.
/* Smooth hover scale on an SVG icon */
.svg-icon {
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transform-origin: center;
}
.svg-icon:hover {
transform: scale(1.15);
}
/* Color transition on SVG path */
.svg-icon path {
transition: fill 0.25s ease-in-out,
stroke 0.25s ease-in-out;
fill: #6366f1;
}
.svg-icon:hover path {
fill: #818cf8;
}
Pro Tip: Always set transform-origin explicitly on SVG elements. Unlike HTML elements that default to their center, SVG elements default to the SVG viewport origin (0, 0), which causes unexpected rotation and scale behavior.
CSS Keyframe Animations: Full Creative Control
Keyframes let you define multi-step animations with precise timing control. They're ideal for loading spinners, pulsing indicators, drawing effects, and looping background animations.
/* Pulsing notification dot */
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.4);
opacity: 0.6;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.notification-dot {
animation: pulse 2s ease-in-out infinite;
transform-origin: center;
}
/* SVG path drawing effect using stroke-dasharray */
@keyframes draw-path {
from {
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 0;
}
}
.draw-line {
stroke-dasharray: 1000;
animation: draw-path 2.5s ease-out forwards;
}
The stroke-dasharray drawing technique is one of the most popular SVG animations on the web. It works by setting the dash length equal to the total path length, then animating the offset from full to zero -- creating the illusion that the path is being drawn in real time.
CSS Transforms: The Performance Sweet Spot
Transforms are the most performant CSS properties to animate because they're handled entirely by the GPU compositor thread. Here are the key transforms for SVG work:
/* Rotation animation */
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Combined transforms for complex motion */
@keyframes float-and-rotate {
0% {
transform: translateY(0px) rotate(0deg);
}
25% {
transform: translateY(-10px) rotate(5deg);
}
50% {
transform: translateY(-18px) rotate(0deg);
}
75% {
transform: translateY(-10px) rotate(-5deg);
}
100% {
transform: translateY(0px) rotate(0deg);
}
}
.floating-element {
animation: float-and-rotate 4s ease-in-out infinite;
transform-origin: center;
}
The Compositor-Safe Properties: Only transform and opacity are guaranteed to run on the compositor thread. Animating fill, stroke, width, height, or d (path data) triggers layout recalculations and can cause jank on complex pages. Stick to transforms and opacity whenever possible.
JavaScript Animation Approaches
When CSS reaches its limits -- dynamic values, scroll-based triggers, physics simulations, or complex sequenced timelines -- JavaScript takes over.
The Web Animations API (WAAPI)
The Web Animations API is the native browser solution for JavaScript-driven animations. It provides the same performance benefits as CSS animations (compositor thread execution) with full programmatic control.
// Basic WAAPI animation on an SVG element
const logo = document.querySelector("#svg-logo");
const fadeIn = logo.animate(
[
{ opacity: 0, transform: "translateY(20px) scale(0.95)" },
{ opacity: 1, transform: "translateY(0) scale(1)" }
],
{
duration: 800,
easing: "cubic-bezier(0.22, 1, 0.36, 1)",
fill: "forwards"
}
);
// WAAPI returns a promise -- perfect for sequencing
fadeIn.finished.then(() => {
console.log("Logo animation complete");
animateSubElements();
});
WAAPI shines when you need to pause, reverse, adjust playback rate, or synchronize multiple animations:
// Advanced WAAPI: controlling multiple SVG paths
const paths = document.querySelectorAll(".animate-path");
const animations = [];
paths.forEach((path, index) => {
const length = path.getTotalLength();
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;
const anim = path.animate(
[
{ strokeDashoffset: length },
{ strokeDashoffset: 0 }
],
{
duration: 1500,
delay: index * 200, // Stagger each path
easing: "ease-out",
fill: "forwards"
}
);
animations.push(anim);
});
// Pause all animations
function pauseAll() {
animations.forEach(a => a.pause());
}
// Reverse all animations
function reverseAll() {
animations.forEach(a => a.reverse());
}
// Speed up to 2x
function speedUp() {
animations.forEach(a => { a.playbackRate = 2; });
}
GSAP: The Industry Standard Library
GreenSock Animation Platform (GSAP) remains the most battle-tested animation library in 2026. Its SVG-specific plugins handle edge cases that would take hundreds of lines of custom code.
import { gsap } from "gsap";
// Simple GSAP SVG animation
gsap.from("#hero-svg", {
opacity: 0,
scale: 0.8,
rotation: -5,
duration: 1.2,
ease: "back.out(1.7)",
transformOrigin: "center center"
});
// GSAP Timeline for sequenced animations
const tl = gsap.timeline({ defaults: { ease: "power2.out" } });
tl.from("#bg-circle", { scale: 0, duration: 0.6 })
.from("#icon-paths path", {
strokeDashoffset: 500,
duration: 1,
stagger: 0.15
}, "-=0.3")
.from("#label-text", {
opacity: 0,
y: 15,
duration: 0.5
}, "-=0.5")
.to("#highlight", {
fill: "#6366f1",
duration: 0.4
});
// ScrollTrigger integration
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
gsap.from(".feature-svg", {
scrollTrigger: {
trigger: ".features-section",
start: "top 80%",
toggleActions: "play none none reverse"
},
y: 40,
opacity: 0,
duration: 0.8,
stagger: 0.2
});
Warning: GSAP licensing changed in 2024. The core library and most plugins are free for standard websites, but the commercial "Business Green" license is required for SaaS products that charge end-users for animation features. Always check the current license terms at greensock.com before deploying to production.
SMIL Animations: Still Alive, But Use Sparingly
SMIL (Synchronized Multimedia Integration Language) animations are defined directly inside SVG markup using <animate>, <animateTransform>, and <animateMotion> elements. Chrome deprecated SMIL in 2015 but reversed course -- it remains supported in all major browsers as of 2026.
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="20" fill="#6366f1">
<!-- SMIL pulse animation -->
<animate
attributeName="r"
values="20;25;20"
dur="2s"
repeatCount="indefinite"
/>
<animate
attributeName="opacity"
values="1;0.6;1"
dur="2s"
repeatCount="indefinite"
/>
</circle>
</svg>
SMIL is useful when you need animations embedded directly in standalone SVG files (like animated favicons or SVGs used in <img> tags where CSS and JS can't reach). However, for most web development scenarios, CSS and JavaScript provide better tooling, debugging, and performance control.
A Full Year of Conversions for $49
Starter Annual: 25 conversions every month, $49 for the whole year. That is about $4.08 a month · Cancel anytime
Get the Annual DealPerformance Optimization Deep Dive
Animation performance can make or break a user's experience. A janky animation is worse than no animation at all. Here's how to ensure your SVG animations run at a rock-solid 60fps.
The Compositor Thread Rule
Modern browsers have two main rendering threads: the main thread (handles JavaScript, layout, paint) and the compositor thread (handles final pixel composition). The compositor thread can animate transform and opacity independently, meaning your animations won't stutter even if JavaScript is busy.
/* GOOD: Compositor-thread animations */
.optimized {
transition: transform 0.3s, opacity 0.3s;
}
.optimized:hover {
transform: translateY(-4px) scale(1.02);
opacity: 0.9;
}
/* BAD: Main-thread animations (causes layout thrashing) */
.unoptimized {
transition: top 0.3s, width 0.3s, fill 0.3s;
}
.unoptimized:hover {
top: -4px;
width: 110%;
}
The will-change Property
The will-change property hints to the browser that an element will be animated, allowing it to promote the element to its own compositor layer ahead of time.
/* Promote element to its own layer before animation */
.will-animate {
will-change: transform, opacity;
}
/* Remove after animation completes to free GPU memory */
.animation-done {
will-change: auto;
}
Warning: Don't overuse will-change. Each promoted layer consumes GPU memory. Applying will-change to dozens of elements simultaneously can actually degrade performance. Use it selectively on elements that will definitely animate, and remove it when the animation completes.
Reducing SVG Complexity
Before animating, optimize the SVG itself:
- Simplify paths: Use tools like SVGO or Vectosolve's built-in optimizer to reduce point counts
- Remove hidden elements: Delete layers that are behind opaque fills
- Flatten groups: Unnecessary
<g>nesting adds overhead to transform calculations - Use symbols for repeated shapes:
<use>references are more efficient than duplicated paths
// Measure SVG complexity before animating
const svg = document.querySelector("#my-svg");
const pathCount = svg.querySelectorAll("path").length;
const totalPoints = Array.from(svg.querySelectorAll("path"))
.reduce((sum, p) => {
const d = p.getAttribute("d") || "";
return sum + (d.match(/[MLHVCSQTAZ]/gi) || []).length;
}, 0);
console.log(`Paths: ${pathCount}, Points: ${totalPoints}`);
// Aim for < 500 total points for smooth animation
Accessibility: Respecting User Preferences
Not everyone wants or can tolerate motion on screen. Users with vestibular disorders, motion sensitivity, or simply a preference for reduced motion have a system-level setting you must respect.
The prefers-reduced-motion Media Query
/* Full animation for users who haven't opted out */
@keyframes slide-in {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.animated-element {
animation: slide-in 0.6s ease-out forwards;
}
/* Reduced motion: instant appearance, no movement */
@media (prefers-reduced-motion: reduce) {
.animated-element {
animation: none;
opacity: 1;
}
/* Or provide a subtle fade-only alternative */
.animated-element {
animation: fade-in 0.2s ease-out forwards;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
}
For JavaScript animations, check the preference programmatically:
const prefersReduced = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReduced) {
// Skip animation or use instant transition
element.style.opacity = "1";
} else {
// Run full animation
element.animate(
[{ opacity: 0 }, { opacity: 1 }],
{ duration: 600, easing: "ease-out" }
);
}
// Listen for changes (user can toggle setting live)
window.matchMedia("(prefers-reduced-motion: reduce)")
.addEventListener("change", (event) => {
if (event.matches) {
document.getAnimations().forEach(a => a.cancel());
}
});
WCAG 2.2 Success Criterion 2.3.3 (added in 2023) recommends that motion animation triggered by interaction can be disabled. This isn't just a nice-to-have -- it's increasingly a legal requirement under accessibility laws in the US, EU, and UK.
CSS vs JavaScript vs AI: Choosing the Right Approach
Not every animation needs the same tool. Here's a practical comparison to help you choose:
| Criteria | CSS Animations | JavaScript (WAAPI/GSAP) | AI-Powered (Vectosolve) |
|---|---|---|---|
| Setup complexity | Zero dependencies | Minimal (WAAPI) to moderate (GSAP) | Upload and configure |
| Performance | Excellent (compositor) | Excellent (WAAPI) / Very good (GSAP) | Excellent (optimized output) |
| Dynamic values | Limited (custom properties) | Full control | AI-determined |
| Timeline sequencing | Complex (delay chaining) | Native support | Automatic |
| Scroll-driven | CSS Scroll Timeline API | ScrollTrigger / Intersection Observer | Configurable |
| Path morphing | Not supported | Requires library (GSAP MorphSVG) | Built-in |
| Learning curve | Low | Moderate to high | Very low |
| Best for | Hover effects, looping, simple transitions | Complex interactions, games, data viz | Rapid prototyping, non-developers |
| File size impact | 0 KB | 0 KB (WAAPI) / ~30 KB (GSAP) | Varies |
| Browser support | Universal | Universal (WAAPI 95%+) | Universal (generates standard code) |
Rule of thumb: Start with CSS. Move to WAAPI when you need programmatic control. Reach for GSAP when you need timelines, morphing, or scroll triggers. Use AI tools when you need speed or when the animation logic exceeds your time budget.
Free SVG Tools for Crafters
Design Checker · Color Separator · Mat Preview · Offset Generator · Text to SVG
Check Your SVG FreePractical Example: Animated SVG Dashboard Icon
Let's put it all together with a real-world example -- an animated dashboard icon that draws itself on load, pulses to indicate activity, and respects reduced motion preferences.
<svg
class="dashboard-icon"
viewBox="0 0 64 64"
width="64"
height="64"
role="img"
aria-label="Dashboard activity indicator"
>
<circle
class="icon-bg"
cx="32" cy="32" r="30"
fill="none" stroke="#e0e7ff" stroke-width="2"
/>
<path
class="icon-chart"
d="M18 44 L26 32 L34 38 L46 20"
fill="none" stroke="#6366f1" stroke-width="2.5"
stroke-linecap="round" stroke-linejoin="round"
/>
<circle
class="icon-dot"
cx="46" cy="20" r="3"
fill="#6366f1"
/>
</svg>
/* Drawing animation */
.icon-chart {
stroke-dasharray: 80;
stroke-dashoffset: 80;
animation: draw 1.2s ease-out 0.3s forwards;
}
@keyframes draw {
to { stroke-dashoffset: 0; }
}
/* Dot appears after line draws */
.icon-dot {
opacity: 0;
transform-origin: 46px 20px;
animation: pop-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 1.4s forwards;
}
@keyframes pop-in {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Continuous pulse on the dot */
.icon-dot {
animation:
pop-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 1.4s forwards,
pulse-dot 2s ease-in-out 2s infinite;
}
@keyframes pulse-dot {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.3); }
}
/* Accessibility */
@media (prefers-reduced-motion: reduce) {
.icon-chart {
animation: none;
stroke-dashoffset: 0;
}
.icon-dot {
animation: none;
opacity: 1;
}
}
Framework Integration: React and Next.js
In modern React and Next.js applications, SVG animations require a slightly different approach due to the virtual DOM and component lifecycle.
import { useRef, useEffect } from "react";
function AnimatedIcon({ isActive }) {
const pathRef = useRef(null);
useEffect(() => {
const path = pathRef.current;
if (!path) return;
const prefersReduced = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReduced) {
path.style.strokeDashoffset = "0";
return;
}
const length = path.getTotalLength();
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;
const animation = path.animate(
[{ strokeDashoffset: length }, { strokeDashoffset: 0 }],
{ duration: 1200, easing: "ease-out", fill: "forwards" }
);
return () => animation.cancel();
}, [isActive]);
return (
<svg viewBox="0 0 64 64" role="img" aria-label="Status">
<path
ref={pathRef}
d="M18 44 L26 32 L34 38 L46 20"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
/>
</svg>
);
}
Key Takeaways and Next Steps
SVG animation in 2026 sits at the intersection of performance, accessibility, and creativity. The tooling has never been more mature:
- Start with CSS for simple hover effects, loading states, and looping animations
- Graduate to the Web Animations API when you need dynamic control, sequencing, or playback manipulation
- Adopt GSAP for complex timelines, scroll-driven animations, and SVG-specific features like path morphing
- Consider AI-powered tools like Vectosolve's SVG Animator for rapid prototyping and automated optimization
- Always optimize by sticking to compositor-safe properties and respecting
prefers-reduced-motion
The best SVG animation is one the user barely notices -- it feels natural, loads instantly, and gracefully degrades for those who prefer stillness. Master these techniques, and you'll build interfaces that don't just function, but truly come alive.
Pro Tip: Ready to animate your SVGs without writing code? Try Vectosolve's AI SVG Animator to generate production-ready CSS and JavaScript animations from any SVG file. Upload your SVG, describe the animation you want, and get optimized code in seconds.
| Property | Composited (Fast) | Layout-Triggering (Slow) |
|---|---|---|
| transform | Yes — GPU accelerated | No |
| opacity | Yes — GPU accelerated | No |
| width / height | No | Yes — triggers reflow |
| top / left | No | Yes — triggers reflow |
| fill / stroke | No | Repaint only (moderate) |