Animated Success Checkmark — SVG Draw HTML CSS

Animated Success Checkmark · Animations · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Pure SVG stroke-draw animation
The circle and tick draw themselves via stroke-dasharray/dashoffset — no images, GIFs, or animation library.
Sequenced choreography
Circle draws first, the tick lands after it completes, then a pulse ring and staggered text — a deliberate sequence.
Physical easing
A cubic-bezier ease accelerates into each draw and settles at the end, feeling intentional rather than mechanical.
One-shot pulse ring
A faint ring scales and fades once when the tick lands, emphasizing the moment of completion.
Staggered text reveal
The heading and description fade and rise in just after the check, guiding the eye through the confirmation.
Clean replay
Clones the SVG and uses the forced-reflow pattern to restart CSS animations reliably on demand.
Crisp and recolorable
The SVG scales sharply to any size via its viewBox and inherits the success color from CSS.
Zero dependencies, tiny footprint
A few lines of SVG and CSS replace a heavy GIF or Lottie player for a simple success state.

About this UI Snippet

Animated Success Checkmark — Stroke-Drawn SVG Tick with Pulse Ring

Screenshot of the Animated Success Checkmark snippet rendered live

The animated green checkmark that draws itself after a successful payment, signup, or save is a tiny moment of delight that makes a confirmation feel earned rather than abrupt. This snippet builds that effect with pure SVG and CSS — no library, no images — using the classic stroke-dash drawing technique, plus a soft pulse ring and staggered text reveal, wrapped in a confirmation card with a replay button.

How the draw-on effect works

The checkmark is a single SVG with two shapes: a <circle> and a <path> for the tick. Both are animated with the stroke-dasharray / stroke-dashoffset technique — the foundation of every "self-drawing" SVG. stroke-dasharray is set to the shape's total length (151 for the circle's circumference, ~40 for the tick path), which turns the stroke into a single dash exactly as long as the line. stroke-dashoffset starts equal to that length, pushing the entire dash out of view, and animates to zero — which slides the dash into place, making the line appear to draw itself from start to end. The circle draws first; the tick starts at a 0.5s delay so it lands *after* the circle completes, reading as "outline, then confirm."

Easing that feels physical

Both animations use cubic-bezier(.65,0,.45,1) — a smooth ease that accelerates into the draw and settles at the end, which feels more deliberate than a linear sweep. The tick uses stroke-linecap: round and stroke-linejoin: round so the drawn line has soft ends, matching the rounded aesthetic of modern confirmation UIs.

The pulse ring and text stagger

When the tick lands, a faint green ring scales up and fades out once (ascPulse), giving the checkmark a subtle "pop" of emphasis at exactly the moment of completion. The heading and description fade and rise in just after (ascText at 0.5s and 0.62s delays), so the eye follows the sequence: circle draws → tick draws → ring pulses → text appears. This choreography is what separates a polished confirmation from a static green icon.

Replaying a CSS animation cleanly

CSS animations only run once on load, so re-triggering them is the tricky part. The replay button clones the SVG and replaces the original — a fresh element restarts its animations from scratch — and re-triggers the pulse and text with the forced-reflow pattern (void element.offsetWidth between removing and re-adding the class), which flushes the style change so the browser treats the re-added animation as new. This is the standard, reliable way to restart a CSS animation on demand.

Why SVG stroke animation over a GIF or Lottie

A stroke-animated SVG is a few lines of markup, scales crisply to any size, inherits color from CSS, weighs nothing, and needs no runtime library — unlike a GIF (fixed resolution, large file, no transparency control) or a Lottie JSON (requires a player library). For a simple checkmark, the native technique is the right tool, and it's trivial to recolor (swap the green) or resize (the viewBox keeps it sharp) for any brand.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out the stroke-length math by hand — paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the circle's stroke-dasharray is set to roughly 151 while the check path's is around 40, and how those specific numbers relate to the actual geometry (the circle's circumference versus the check path's drawn length) rather than being arbitrary. The same assistant is useful for optimizing it — asking whether the clone-and-replace technique used to replay the SVG has any downsides versus using the Web Animations API's own restart capabilities. It's just as good for extending it: ask it to add a subtle confetti burst timed to the pulse ring, generalize the component so the same choreography works for an error or warning variant with a different icon path, or wire the replay trigger to fire automatically whenever a real async success event resolves instead of only via the manual button. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an "animated success checkmark" confirmation card in plain HTML, CSS, and JavaScript — no libraries, using SVG stroke-drawing, a one-shot pulse ring, and a clean replay mechanism.

Requirements:
- A card containing an SVG success mark made of a circle and a checkmark path, plus a heading and description text, and a separate "replay" button outside the card.
- Set each SVG shape's stroke-dasharray to match its own real length (the circle's circumference for the circle, the path's drawn length for the check) and its stroke-dashoffset to start at that same value so the shape is fully hidden, then animate stroke-dashoffset to zero via CSS keyframes so each shape appears to draw itself on. The circle must finish drawing before the checkmark path begins, using a deliberate animation-delay on the check so the sequence reads as outline-then-tick, not both at once.
- Add a separate ring element, initially invisible, positioned concentrically around the mark, that plays a single keyframe animation scaling up from a slightly-shrunk state to a slightly-enlarged state while fading its opacity from partial to zero, timed to start right as the checkmark finishes drawing, giving a one-time "pulse" effect. This ring must be created and appended via JavaScript (not present in the initial HTML) so that replaying the sequence is a clean reset.
- Fade and slide the heading and description into view with their own staggered delays, timed to happen just after the pulse starts, so the full sequence is: circle draws, checkmark draws, pulse ring plays, then text settles in.
- Implement a replay function that: clones the SVG element and replaces the original in the DOM (since CSS animations do not restart merely by toggling a class) to restart the stroke-drawing keyframes from scratch, and separately restarts the pulse ring's animation using the forced-reflow pattern (remove its trigger class, read a layout property like offsetWidth to force a reflow, then re-add the class).
- Trigger the pulse (but not a full replay) automatically once via requestAnimationFrame right after the page loads, so the first playthrough is synced correctly with the CSS keyframes without needing a manual click.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA confirmation card renders and immediately plays: the circle draws, the tick draws, a ring pulses, and the text fades in.
  2. 2
    Watch the sequenceNote the choreography — circle outline first, then the checkmark, then the pulse and staggered heading/description.
  3. 3
    Replay itClick "Replay animation" to restart the whole sequence cleanly from the beginning.
  4. 4
    Recolor itChange the green (#22c55e) on the circle, check, and pulse to match your brand's success color.
  5. 5
    Resize itAdjust the .asc-mark width/height — the SVG viewBox keeps the stroke crisp at any size.
  6. 6
    Trigger it on a real eventShow the card (or call the play() function) after a successful API response — a payment, signup, or save.

Real-world uses

Common Use Cases

Payment and checkout confirmation
Confirm a successful order or payment — pair with a confetti celebration card for a bigger moment.
Form submission success
Replace a plain "Thanks!" with a drawn checkmark after a contact or signup form submits.
Save and sync indicators
Show a quick checkmark when a document saves or settings sync, reinforcing a form autosave indicator.
Onboarding step completion
Mark a completed onboarding step or task with a satisfying draw-on tick.
Email and subscription confirmation
Confirm a verified email or completed subscription with an animated success state.
Learning SVG stroke animation
A clear reference for the stroke-dasharray draw technique and CSS animation restart — compare with an SVG progress ring for the gauge variant.

Got questions?

Frequently Asked Questions

Each shape's stroke-dasharray is set to its total length, turning the outline into one dash exactly as long as the line. stroke-dashoffset starts at that same length (pushing the dash out of sight) and animates to 0, which slides the dash into view so the line appears to draw itself. The circle's length is its circumference (2πr ≈ 151 for r=24) and the tick's is its path length (~40).

Hide the card initially, then reveal it (or mount the component) when your success event fires — a successful fetch response, a completed payment webhook, a saved form. Because CSS animations run on element insertion/load, showing the card plays the sequence; to replay without remounting, call the play() function which restarts the animations.

CSS animations only run once per element load and don't restart on a class toggle alone. Replacing the element with a fresh clone gives the browser a new element that runs its animations from scratch. For the non-SVG parts (pulse, text) the forced-reflow trick — remove class, read offsetWidth, re-add class — flushes styles so the re-added animation is treated as new.

Recolor by changing #22c55e on the .asc-circle, .asc-check, and .asc-pulse to your success color. Resize via the .asc-mark width/height — the SVG viewBox ("0 0 52 52") keeps the stroke crisp at any scale. If you change the circle radius, recompute its dasharray to the new circumference (2πr).

In React, render the SVG in JSX and key it on a success counter so a new key remounts and replays the animation; in Vue, use a :key bound to a trigger ref; in Angular, use *ngIf to mount on success or a key-like trick. The CSS and stroke-dash technique are framework-agnostic — only the replay/remount mechanism uses each framework's reconciliation.