Back to Documentation
Developer Guide10 min readFebruary 19, 2026

SVG Animations: The Complete Guide

Add, control, strip, and ship CSS animations on your SVG icons, zero JavaScript required.

I

Icora Engineering

Engineering

Animated SVG icons with CSS keyframes

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

Code
<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.

AnimationDescriptionDefault Duration
drawPaths draw themselves from start to end (stroke-dasharray)1500ms
fade-inSmooth opacity 0 → 1 transition600ms
popQuick scale-up with elastic overshoot400ms
bounceSpring-like entry with bounce800ms
rubber-bandElastic squash & stretch entrance900ms
flip3D-style Y-axis flip entrance700ms
slide-inSlide up from below with fade600ms
zoom-inSmooth scale-up without overshoot500ms
typewriterLeft-to-right clip-path reveal800ms
morph-inBlur-to-clear focus entrance700ms

Attention Animations (8)

Play once to grab attention, then reset. Great for notifications, errors, or interactive feedback.

AnimationDescriptionDefault Duration
shakeHorizontal shake600ms
swingPendulum swing rotation1000ms
jelloWobbly jello-like skew900ms
tadaCelebratory scale + rotate combo1000ms
heartbeatDouble-pulse like a real heartbeat1400ms
wiggleQuick micro-rotation oscillation500ms
wobbleLarge asymmetric side-to-side wobble1000ms
head-shakeSubtle horizontal "no" gesture800ms

Continuous Animations (6)

Loop infinitely. Use for loading indicators, ambient effects, or decorative motion.

AnimationDescriptionDefault Duration
pulseGentle breathing scale effect2000ms
floatUp/down floating motion3000ms
spinContinuous 360° rotation2000ms
blinkFlashing opacity on/off1200ms
breatheStroke + fill opacity breathing pulse3000ms
color-cycleContinuous hue rotation through all colors4000ms

Exit Animations (2)

Play once to remove the icon. Use animation-fill-mode: forwards to hold the invisible end state.

AnimationDescriptionDefault Duration
fade-outSmooth opacity fade to invisible600ms
slide-outSlide down with fade exit600ms

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.

OptionValuesWhat It Does
durationNumber (ms)Total animation time. Lower = snappier, higher = smoother.
delayNumber (ms)Wait before starting. Useful for sequencing multiple icons.
staggerNumber (ms)Delay between each path element inside the icon. Creates a cascading reveal effect.
easingCSS easing stringTiming function. e.g. "ease-out", "cubic-bezier(0.34, 1.56, 0.64, 1)"
iterationsNumber or "infinite"How many times to play. Entrance presets default to 1, continuous to infinite.
directionnormal | reverse | alternate | alternate-reversePlayback direction. "alternate" bounces back and forth between start and end states.
fillModeforwards | backwards | both | noneWhether the animation holds its end state (forwards), start state (backwards), or neither (none).
hoverOnlytrue | falseIf 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)

Code
<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)

Code
<!-- 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

Code
.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

ValueBehaviorUse Case
"running"Animation plays (default)Normal auto-play on load
"paused"Animation frozen at current framePause while off-screen, resume on scroll-in
"hover"Paused by default, plays on :hoverInteractive icons, button hover effects

JavaScript Examples

Code
// 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

Code
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)

Code
// 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

Code
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.

Code
// 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

QuestionAnswer
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 Free
Tags:SVG animationCSS animationanimated iconsicon animationdata-icora-animate

Found 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