SVG Interactions & Animation
SVG elements are part of the DOM, which means every CSS technique you have learned applies directly to them. You can hover a path, focus a group, transition a fill, and run keyframe animations on shapes exactly as you would on a <div>. This makes SVG one of the most flexible tools for creating interactive graphics, icons, and illustrations that respond naturally to user input.
SVG also opens up animation techniques that are impossible with regular HTML elements. Path drawing effects, morphing shapes, and animating strokes along a curve are all native to SVG and driven entirely with CSS properties. This reading covers the full range: from simple hover states to the stroke-dashoffset technique that makes paths appear to draw themselves.
Targeting SVG Elements with CSS
Inline SVG elements — those written directly in your HTML rather than referenced via <img> — are fully accessible to CSS. You can target them by element name, class, or ID just like any other element.
/* Target all circles in an SVG */
circle {
fill: #3b82f6;
transition: fill 200ms ease;
}
/* Target a specific path by class */
.icon-arrow {
stroke: currentColor;
stroke-width: 2;
}
/* Hover state on an SVG group */
.icon-group:hover .icon-arrow {
stroke: #3b82f6;
}
SVG has its own set of presentation attributes alongside the standard CSS ones you already know. The most important ones for animation are fill, stroke, stroke-width, and opacity. All of these are animatable with both transitions and keyframes.
CSS can only reach inside an SVG when it is inline in the HTML. An SVG loaded via <img src="icon.svg"> is treated as an opaque image — you cannot style or animate its internal elements from your stylesheet. If you need interactive or animated SVG, it must be inline.
currentColor
The currentColor keyword is especially powerful with SVG. It causes a fill or stroke to inherit the element's color CSS property, which means you can control an entire icon's color from a single rule and get transitions for free.
.icon {
color: #64748b;
transition: color 200ms ease;
}
.icon:hover {
color: #3b82f6;
}
/* SVG paths inside .icon inherit automatically */
.icon path,
.icon circle {
fill: currentColor;
}
Hover and Focus States
SVG elements respond to :hover and :focus the same way HTML elements do. The selector targets the SVG element itself or any element inside it. Combining this with CSS transitions produces interactive icons and illustrations with very little code.
.btn-icon {
fill: #94a3b8;
transition:
fill 200ms ease,
transform 200ms ease;
transform-origin: center;
}
.btn-icon:hover {
fill: #3b82f6;
transform: scale(1.15);
}
.btn-icon:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 4px;
}
SVG elements use a different coordinate system than HTML elements. By default, transform-origin on an SVG element is relative to the SVG viewport origin (top-left), not the element's own center. Set transform-origin: center or use explicit coordinates to get the transform behavior you expect.
Hover Demo
Hover over each icon below to see fill, stroke, and scale transitions applied to inline SVG elements.
Keyframe Animations on SVG
@keyframes work on SVG elements exactly as they do on HTML elements. You can animate transform, opacity, fill, and stroke. The same performance principles apply: prefer transform and opacity for smooth compositor-friendly animation.
@keyframes icon-bounce {
0%, 100% { transform: translateY(0); }
40% { transform: translateY(-8px); }
60% { transform: translateY(-4px); }
}
@keyframes icon-spin {
to { transform: rotate(360deg); }
}
@keyframes icon-pulse-fill {
0%, 100% { fill: #3b82f6; }
50% { fill: #60a5fa; opacity: 0.7; }
}
.loading-icon {
animation: icon-spin 1s linear infinite;
transform-origin: center;
}
.notification-icon {
animation: icon-bounce 1s ease-in-out infinite;
transform-origin: center;
}
One important distinction: SVG elements inside a group (<g>) can be animated independently or as a unit. Animating the group transforms all children together, while animating individual elements gives you fine-grained control over each part of an illustration.
Path Drawing with stroke-dasharray and stroke-dashoffset
The path drawing effect — where a line appears to write itself — is one of the most recognizable SVG animation techniques. It uses two SVG stroke properties together: stroke-dasharray and stroke-dashoffset.
How It Works
stroke-dasharray defines a pattern of dashes and gaps along a stroke. If you set its value to the exact total length of the path, the entire stroke becomes one single dash. stroke-dashoffset then shifts that dash forward along the path. At full offset, the dash is shifted completely off the visible portion of the path and the stroke appears invisible. At zero offset, the dash sits exactly over the path and the full stroke is visible.
Animating stroke-dashoffset from the full path length down to zero makes the path appear to draw itself in from start to finish.
.draw-path {
stroke-dasharray: 300; /* Must match or exceed path length */
stroke-dashoffset: 300; /* Start fully offset (invisible) */
animation: draw 1.5s ease-out forwards;
}
@keyframes draw {
to {
stroke-dashoffset: 0; /* Animate to fully visible */
}
}
Finding Path Length
The exact length of an SVG path is available via JavaScript using getTotalLength(). You can use this to set the values dynamically rather than hardcoding them, which is especially useful when path length may vary.
const path = document.querySelector('.draw-path');
const length = path.getTotalLength();
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;
/* Trigger animation by removing the offset */
path.style.transition = 'stroke-dashoffset 1.5s ease-out';
path.style.strokeDashoffset = 0;
Path Drawing Demo
Click the button to watch the path draw itself using the stroke-dashoffset technique.
Combining SVG Parts for Complex Animations
Real-world SVG animation often involves coordinating multiple elements inside a single SVG. A checkmark animation might draw a circle first, then draw the checkmark path inside it. A logo might have each letter fade in with a staggered delay. You achieve this by targeting individual elements or groups and using animation-delay to sequence them.
@keyframes draw {
to { stroke-dashoffset: 0; }
}
.check-circle {
stroke-dasharray: 283; /* circumference of r=45 circle */
stroke-dashoffset: 283;
animation: draw 600ms ease-out forwards;
}
.check-mark {
stroke-dasharray: 80;
stroke-dashoffset: 80;
animation: draw 400ms ease-out 500ms forwards; /* delayed until circle finishes */
}
The key detail is animation-fill-mode: forwards combined with the delay. Without forwards, the element would snap back to its invisible state once the animation ends. With a delay, you also need animation-fill-mode: backwards (or both) if you want the element to remain hidden in its starting state during the delay period — otherwise it will be briefly visible before the animation begins.
Sequenced Checkmark Demo
Click the button to play a sequenced checkmark animation: the circle draws first, then the check follows.
Performance and Accessibility
SVG animations follow the same performance rules as all CSS animation. Animating transform and opacity on SVG elements is compositor-friendly. Animating fill and stroke triggers repaint but not layout, making them moderately expensive but generally acceptable for short interactions. Avoid animating properties that change the SVG layout geometry, such as width, height, or viewBox.
The stroke-dashoffset technique is an exception worth noting: animating it triggers repaint on every frame because the browser must redraw the stroke. For short one-shot animations this is acceptable, but avoid running it continuously on many elements simultaneously.
Accessibility considerations for SVG animation are identical to those for any CSS animation. Respect prefers-reduced-motion, provide meaningful aria attributes on interactive SVG elements, and ensure that any information conveyed by the animation is also available in a non-animated form. An SVG icon that only communicates its meaning through motion is inaccessible.
@media (prefers-reduced-motion: reduce) {
.draw-path {
stroke-dashoffset: 0; /* Show fully drawn immediately */
transition: none;
animation: none;
}
}
Decorative SVG icons should have aria-hidden="true" so screen readers skip them. Interactive SVG elements that serve as buttons or controls need either a visible text label or an aria-label attribute. Adding role="img" and a <title> element inside the SVG provides a description for assistive technologies when the icon conveys meaningful information.