SVG Store animation

Flowing Success Check

A premium, subtle onboarding success animation that seals first-time wins with a flowing check and brand glow.

Free UI motion
Download
Details

About this animation

Designed for landing page heroes and SaaS dashboards, this animation highlights successful onboarding or completed setup with refined motion and brand-forward colors. The path-reveal checkmark feels handcrafted and confident while the ambient glow adds premium polish without distracting. Lightweight, editable, and ready to drop into your hero or modal to increase conversion and delight.

SVG code
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" role="img" aria-label="Onboarding success animation with flowing checkmark and brand glow">
  <defs>
    <linearGradient id="gradRing" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="#4F46E5"/> <!-- indigo -->
      <stop offset="60%" stop-color="#14B8A6"/> <!-- teal -->
    </linearGradient>
    <radialGradient id="bgRadial" cx="50%" cy="40%" r="60%">
      <stop offset="0%" stop-color="#ffffff" stop-opacity="1"/>
      <stop offset="100%" stop-color="#EEF2FF" stop-opacity="1"/>
    </radialGradient>
    <filter id="blurGlow" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur stdDeviation="8" result="b"/>
      <feMerge>
        <feMergeNode in="b"/>
        <feMergeNode in="SourceGraphic"/>
      </feMerge>
    </filter>
  </defs>

  <style>
    :root{
      --indigo:#4F46E5;
      --teal:#14B8A6;
      --warm:#FFB86B;
      --white:#FFFFFF;
    }

    /* Glow pulse using CSS so we can honor prefers-reduced-motion */
    .glow-pulse{
      filter: url(#blurGlow);
      transform-origin: 100px 100px;
      animation: pulse 1.6s ease-in-out 2.6s 2;
      opacity: 0.9;
    }

    @keyframes pulse{
      0%   { transform: scale(1); opacity:0.9; }
      50%  { transform: scale(1.08); opacity:1; }
      100% { transform: scale(1); opacity:0.92; }
    }

    /* subtle rotation for brand sophistication after reveal */
    .settle{
      transform-origin: 100px 100px;
      animation: settle 1s ease-in-out 3.2s 1 forwards;
    }
    @keyframes settle{
      0% { transform: scale(1) rotate(0deg); }
      50% { transform: scale(1.04) rotate(2deg); }
      100%{ transform: scale(1) rotate(0deg); }
    }

    /* Reduced motion: stop CSS animations and ensure final visible state */
    @media (prefers-reduced-motion: reduce) {
      .glow-pulse, .settle { animation: none; opacity: 1; transform: none; }
    }
  </style>

  <!-- soft white card backdrop -->
  <rect x="10" y="18" width="180" height="164" rx="14" fill="url(#bgRadial)" stroke-opacity="0.04"/>

  <!-- outer brand ring (path reveal by stroke-dashoffset) -->
  <g class="settle">
    <circle cx="100" cy="100" r="70" fill="none" stroke="url(#gradRing)" stroke-width="8" stroke-linecap="round" stroke-dasharray="440" stroke-dashoffset="440">
      <!-- draw ring in: 0 - 1s -->
      <animate attributeName="stroke-dashoffset" begin="0s" dur="1s" to="0" fill="freeze"/>
    </circle>

    <!-- ambient glow behind ring -->
    <circle class="glow-pulse" cx="100" cy="100" r="76" fill="none" stroke="url(#gradRing)" stroke-width="10" opacity="0.0">
      <!-- fade up to visible when ring drawn -->
      <animate attributeName="opacity" begin="1s" dur="0.6s" from="0" to="0.22" fill="freeze"/>
    </circle>

    <!-- inner soft highlight -->
    <circle cx="100" cy="100" r="58" fill="rgba(255,255,255,0.0)" stroke="none"/>

    <!-- checkmark path (path reveal) -->
    <path id="check" d="M72 102 L92 122 L132 82" fill="none" stroke="var(--warm)" stroke-width="9" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="220" stroke-dashoffset="220">
      <!-- reveal check from 1.0s to 2.6s (1.6s duration) -->
      <animate attributeName="stroke-dashoffset" begin="1s" dur="1.6s" to="0" fill="freeze"/>
    </path>

    <!-- subtle trailing teal accent along the check to imply flow -->
    <path d="M72 102 L92 122 L132 82" fill="none" stroke="rgba(20,184,166,0.18)" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="220" stroke-dashoffset="220">
      <animate attributeName="stroke-dashoffset" begin="1.2s" dur="1.4s" to="0" fill="freeze"/>
    </path>

    <!-- warm accent dot that appears at stroke end to accentuate completion -->
    <circle cx="132" cy="82" r="6" fill="var(--warm)" opacity="0">
      <animate attributeName="opacity" begin="2.6s" dur="0.18s" from="0" to="1" fill="freeze"/>
      <animate attributeName="r" begin="2.6s" dur="0.4s" values="2;8;6" keyTimes="0;0.6;1" fill="freeze"/>
    </circle>

    <!-- tiny sparkles that pop after completion -->
    <g opacity="0">
      <circle cx="86" cy="70" r="2.5" fill="#FFDEC7">
        <animate attributeName="opacity" begin="2.7s" dur="0.35s" from="0" to="1" fill="freeze"/>
        <animate attributeName="cy" begin="2.7s" dur="0.6s" from="70" to="60" fill="freeze"/>
      </circle>
      <circle cx="122" cy="48" r="2" fill="#C7F7EF">
        <animate attributeName="opacity" begin="2.85s" dur="0.3s" from="0" to="1" fill="freeze"/>
        <animate attributeName="cx" begin="2.85s" dur="0.6s" from="122" to="128" fill="freeze"/>
      </circle>
      <animate attributeName="opacity" begin="2.7s" dur="0.01s" to="1" fill="freeze"/>
    </g>
  </g>

  <!-- final subtle shadow anchor -->
  <ellipse cx="100" cy="154" rx="42" ry="8" fill="#0f172a" opacity="0.03">
    <animate attributeName="opacity" begin="2.6s" dur="0.8s" from="0" to="0.03" fill="freeze"/>
  </ellipse>
</svg>