SVG Animations: The Complete Guide
Add, control, strip, and ship CSS animations on your SVG icons, zero JavaScript required.
Icora Engineering
Engineering

Icora icons can ship with built-in CSS animations, entrance effects, looping motions, hover triggers, and more. The animations live entirely inside the SVG as a self-contained <style> block. No external CSS files, no JavaScript runtime, no Lottie player. Just drop the SVG in and it animates.
This guide covers everything: how the animation system works under the hood, how to apply animations in the Studio, how they flow through the marketplace, and how developers can control playback from external code.
How SVG Animations Work
When you assign an animation to an icon, Icora injects a <style> block directly inside the <svg> element. This block contains CSS @keyframes and class-based animation rules. The SVG remains a single, self-contained file.
What Gets Injected
<svg viewBox="0 0 24 24" class="icora-anim-abc"
data-icora-animate="running">
<style>
@keyframes icora-fade-in-abc {
from { opacity: 0; }
to { opacity: 1; }
}
.icora-anim-group-abc {
animation: icora-fade-in-abc 600ms ease-out forwards;
transform-origin: 12px 12px;
}
/* Respects user motion preferences */
@media (prefers-reduced-motion: reduce) {
[class*="icora-"] {
animation-duration: 0.01ms !important;
}
}
</style>
<g class="icora-anim-group-abc">
<path d="M12 2L2 22h20L12 2z" />
</g>
</svg>- **@keyframes**: The animation definition (transform, opacity, color, etc.)
- **Animation classes**: Applied to a wrapper <g> element around the icon content
- **Unique IDs**: Each injection gets a random suffix (e.g. "abc") to prevent collisions when multiple animated SVGs exist on the same page
- **Reduced motion**: Every animated SVG includes a @media query that respects the user's prefers-reduced-motion setting
- **data-icora-animate**: A control attribute on the SVG root for external playback control
Pro Tip
Because animations are pure CSS inside the SVG, they work everywhere SVGs work, browsers, email clients (that support SVG), design tools, and any platform that renders inline SVGs.
Available Animations (26 Presets)
Icora ships with 26 animation presets across 4 categories. Each preset has carefully tuned defaults for duration, easing, and stagger timing.
Entrance Animations (10)
Play once when the icon first appears. Use animation-fill-mode: forwards to hold the final state.
| Animation | Description | Default Duration |
|---|---|---|
| draw | Paths draw themselves from start to end (stroke-dasharray) | 1500ms |
| fade-in | Smooth opacity 0 → 1 transition | 600ms |
| pop | Quick scale-up with elastic overshoot | 400ms |
| bounce | Spring-like entry with bounce | 800ms |
| rubber-band | Elastic squash & stretch entrance | 900ms |
| flip | 3D-style Y-axis flip entrance | 700ms |
| slide-in | Slide up from below with fade | 600ms |
| zoom-in | Smooth scale-up without overshoot | 500ms |
| typewriter | Left-to-right clip-path reveal | 800ms |
| morph-in | Blur-to-clear focus entrance | 700ms |
Attention Animations (8)
Play once to grab attention, then reset. Great for notifications, errors, or interactive feedback.
| Animation | Description | Default Duration |
|---|---|---|
| shake | Horizontal shake | 600ms |
| swing | Pendulum swing rotation | 1000ms |
| jello | Wobbly jello-like skew | 900ms |
| tada | Celebratory scale + rotate combo | 1000ms |
| heartbeat | Double-pulse like a real heartbeat | 1400ms |
| wiggle | Quick micro-rotation oscillation | 500ms |
| wobble | Large asymmetric side-to-side wobble | 1000ms |
| head-shake | Subtle horizontal "no" gesture | 800ms |
Continuous Animations (6)
Loop infinitely. Use for loading indicators, ambient effects, or decorative motion.
| Animation | Description | Default Duration |
|---|---|---|
| pulse | Gentle breathing scale effect | 2000ms |
| float | Up/down floating motion | 3000ms |
| spin | Continuous 360° rotation | 2000ms |
| blink | Flashing opacity on/off | 1200ms |
| breathe | Stroke + fill opacity breathing pulse | 3000ms |
| color-cycle | Continuous hue rotation through all colors | 4000ms |
Exit Animations (2)
Play once to remove the icon. Use animation-fill-mode: forwards to hold the invisible end state.
| Animation | Description | Default Duration |
|---|---|---|
| fade-out | Smooth opacity fade to invisible | 600ms |
| slide-out | Slide down with fade exit | 600ms |
Customization Options
Every animation preset uses sensible defaults, but you can override them per icon. These options are available in the Studio animation panel and are preserved through export.
| Option | Values | What It Does |
|---|---|---|
| duration | Number (ms) | Total animation time. Lower = snappier, higher = smoother. |
| delay | Number (ms) | Wait before starting. Useful for sequencing multiple icons. |
| stagger | Number (ms) | Delay between each path element inside the icon. Creates a cascading reveal effect. |
| easing | CSS easing string | Timing function. e.g. "ease-out", "cubic-bezier(0.34, 1.56, 0.64, 1)" |
| iterations | Number or "infinite" | How many times to play. Entrance presets default to 1, continuous to infinite. |
| direction | normal | reverse | alternate | alternate-reverse | Playback direction. "alternate" bounces back and forth between start and end states. |
| fillMode | forwards | backwards | both | none | Whether the animation holds its end state (forwards), start state (backwards), or neither (none). |
| hoverOnly | true | false | If true, animation only plays on :hover. Paused by default. |
Pro Tip
The "stagger" option is what makes icon animations feel alive. A 60ms stagger on a 5-path icon creates a ripple effect where each path appears slightly after the previous one. Try it with "fade-in" or "draw" for best results.
Animations in the Marketplace
When a creator publishes an animated icon pack to the marketplace, the animations are baked into the SVG content at publish time. This means buyers get the exact animation the creator intended, per icon.
For Sellers
- **Assign animations before publishing**: Use the Studio animation panel to assign different animations to different icons in your pack.
- **Animations are baked at publish time**: The CSS is injected into each SVG when you hit "Publish". Your original project files are not modified.
- **The "Animated" badge**: Packs with animations automatically get a purple "Animated" badge on the marketplace card and detail page.
- **It's a selling point**: Animated packs stand out in the marketplace grid. The badge is visible at a glance.
For Buyers
- **You are not locked into animations**: Every animated pack can be downloaded with or without animations.
- **"Animations ON" (default)**: Download with the creator's per-icon animations preserved.
- **"Animations OFF"**: Strips all animation CSS and wrapper elements. You get clean, static SVGs, identical to what you'd get from a non-animated pack.
- **"Replace Animation"**: Strip the creator's animations and apply a different animation of your choice to all icons.
- **The choice is per-download**: You can download the same pack twice, once animated, once static.
Warning
When downloading with "Animations OFF", the stripAnimations function removes all Icora-specific CSS, wrapper <g> elements, and data attributes. The resulting SVG is as clean as if it was never animated.
Embedding: How to Use Animated SVGs
Animated SVGs work differently depending on how you embed them. This is the most important section for developers.
Method 1: <img> Tag (Simplest)
<img src="/icons/rocket.svg" alt="Rocket" width="48" height="48" />- **Animation auto-plays**: The CSS inside the SVG triggers immediately on load.
- **No external control**: The SVG is sandboxed. You cannot pause, resume, or modify the animation from outside.
- **Best for**: Static pages, marketing sites, email templates, anywhere you want "fire and forget" animation.
Method 2: Inline SVG (Full Control)
<!-- Paste the SVG directly in your HTML -->
<svg viewBox="0 0 24 24" class="icora-anim-abc"
data-icora-animate="running">
<style>/* animation CSS */</style>
<g class="icora-anim-group-abc">
<path d="..." />
</g>
</svg>- **Full control**: The SVG is part of your DOM. External JS and CSS can reach inside.
- **data-icora-animate**: Use this attribute to control playback (see next section).
- **Best for**: Web apps, interactive UIs, React/Vue/Svelte components, anywhere you need programmatic control.
Method 3: CSS background-image
.icon {
background-image: url("/icons/rocket.svg");
width: 48px;
height: 48px;
}- **Animation auto-plays**: Same as <img>, the internal CSS triggers on load.
- **No external control**: Background images are fully sandboxed.
- **Best for**: CSS-only designs, pseudo-elements, decorative backgrounds.
Controlling Animations from Code
When using inline SVGs, every animated icon includes a data-icora-animate attribute on the <svg> root. This attribute controls animation playback via CSS animation-play-state, with no JavaScript required inside the SVG.
The data-icora-animate Attribute
| Value | Behavior | Use Case |
|---|---|---|
| "running" | Animation plays (default) | Normal auto-play on load |
| "paused" | Animation frozen at current frame | Pause while off-screen, resume on scroll-in |
| "hover" | Paused by default, plays on :hover | Interactive icons, button hover effects |
JavaScript Examples
// Get the SVG element
const icon = document.querySelector('svg[data-icora-animate]');
// Pause animation
icon.dataset.icoraAnimate = "paused";
// Resume animation
icon.dataset.icoraAnimate = "running";
// Switch to hover-only mode
icon.dataset.icoraAnimate = "hover";React Example
function AnimatedIcon({ svg, paused }) {
return (
<div
dangerouslySetInnerHTML={{ __html: svg }}
ref={(el) => {
const svgEl = el?.querySelector("svg");
if (svgEl) {
svgEl.dataset.icoraAnimate = paused
? "paused"
: "running";
}
}}
/>
);
}Intersection Observer (Play on Scroll)
// Play animation only when icon scrolls into view
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const svg = entry.target.querySelector("svg");
if (svg) {
svg.dataset.icoraAnimate = entry.isIntersecting
? "running"
: "paused";
}
});
});
document.querySelectorAll(".icon-wrapper").forEach(el => {
observer.observe(el);
});Pro Tip
The data-icora-animate API works because every animated SVG includes internal CSS rules that respond to the attribute value. The rules use animation-play-state: paused/running, no JavaScript runs inside the SVG itself.
Stripping Animations Programmatically
If you want to remove animations from SVGs in your own build pipeline (outside of Icora), the animation markup follows a predictable pattern that can be stripped with a few regex replacements.
What to Remove
- **<style> blocks**: Any <style> tag containing "icora-" in its content.
- **Wrapper <g> elements**: <g class="icora-anim-group-..."> wrappers, unwrap them (keep inner content).
- **CSS classes**: Any class attribute containing "icora-" prefixed values.
- **Data attribute**: The data-icora-animate attribute on the <svg> root.
- **Empty class attributes**: Clean up leftover class="" after removal.
Example: Node.js Strip Script
function stripIcoraAnimations(svg) {
let result = svg;
// 1. Remove <style> blocks with Icora animations
result = result.replace(
/<style[^>]*>[\s\S]*?icora-[\s\S]*?<\/style>/gi,
""
);
// 2. Unwrap animation <g> wrappers
result = result.replace(
/<g\s+class="icora-anim-group-[^"]*">([\s\S]*?)<\/g>/gi,
"$1"
);
// 3. Remove icora classes
result = result.replace(/\s+class="icora-[^"]*"/gi, "");
// 4. Remove data-icora-animate attribute
result = result.replace(
/\s+data-icora-animate="[^"]*"/gi,
""
);
// 5. Clean up empty class attributes
result = result.replace(/\s+class=""/g, "");
return result;
}Warning
Be careful with regex-based SVG manipulation in production. For critical pipelines, consider using an XML parser instead. The patterns above work reliably for Icora-generated SVGs but may need adjustment for edge cases.
Optimization & Performance
Animated SVGs add a small amount of CSS overhead. Here is what to expect and how to keep things fast.
File Size Impact
- **Typical overhead**: 200-500 bytes of CSS per animated icon.
- **GZIP-friendly**: CSS keyframes compress extremely well. A 400-byte animation block might add only 80-120 bytes after GZIP.
- **No runtime cost**: Unlike Lottie (requires a 50KB+ player) or GSAP (requires a JS library), Icora animations are native CSS, zero JavaScript overhead.
SVG Optimizer Compatibility
Icora's SVG optimizer preserves <style> blocks. It only optimizes path data, attributes, and whitespace, it will never strip your animation CSS. If you use SVGO or another external optimizer, make sure to configure it to preserve <style> elements and class attributes.
// SVGO config, preserve animation CSS
module.exports = {
plugins: [
{
name: "preset-default",
params: {
overrides: {
// Keep <style> blocks intact
inlineStyles: false,
// Don't remove class attributes
removeUnknownsAndDefaults: {
keepDataAttrs: true,
},
// Don't minify CSS (can break keyframe names)
minifyStyles: false,
},
},
},
],
};Accessibility
- **prefers-reduced-motion**: Every animated SVG includes a @media query that reduces animation duration to near-zero when the user has requested reduced motion.
- **Combine with A11y injection**: When downloading, enable both "A11y ON" and "Animations ON", the SVG will have both accessible labels and motion-safe animations.
- **Screen readers**: Animation CSS does not affect screen reader behavior. The ARIA attributes injected by the A11y toggle work independently.
Frequently Asked Questions
| Question | Answer |
|---|---|
| Is animation CSS or JavaScript? | Pure CSS. @keyframes and animation properties inside a <style> block within the SVG. Zero JS. |
| Can I use animated SVGs in React? | Yes. Use dangerouslySetInnerHTML for inline rendering, or import as a React component. The data-icora-animate attribute works with refs. |
| Do animations work in <img> tags? | Yes, they auto-play. But you cannot pause/resume from external code. For control, use inline SVG. |
| What if I need static SVGs? | Toggle "Animations OFF" when downloading from Inventory. The animation CSS and wrapper elements are completely removed. |
| Can two animated SVGs conflict? | No. Each injection uses a random unique ID suffix (e.g. "icora-fade-in-a3f"). Even identical animations on the same page get different keyframe names. |
| Do animations survive SVGO? | Only if you configure SVGO to preserve <style> blocks and class attributes. See the SVGO config example above. |
| Can I add my own CSS on top? | Yes. The animation classes (icora-anim-group-*) are just CSS classes. You can add transitions, filters, or other styles alongside them. |
| What about email clients? | Most modern email clients that support SVG will play the animation. Outlook strips <style> blocks, so the icon appears static there, which is the safe fallback. |
Ready to bring your icons to life? Open any project in the Studio, select an icon, and choose an animation from the panel. Export with animations enabled and ship them today.
Try Icora FreeFound this helpful? Share it!
Ready to Create Stunning Icons?
Put these principles into practice with Icora's AI-powered icon generator, professional studio tools, and developer-ready export.
Start Creating Free