Success Celebration
SVG circle drawn from 12 o'clock, checkmark traced in, two pulsing halos and a Canvas 2D ring burst — compact toast or full modal, replay on click.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Atmosphere has 57 effects, including 10 free. Explore the category →
3 usage examples



How it works
The sequence starts when .scb-run is added to .scb-root: the SVG circle draws from 12 o'clock via the stroke-dasharray / stroke-dashoffset pair (214 → 0 over 0.52 s, cubic-bezier(0.4,0,0.2,1)); the SVG group is rotated −90° so the stroke begins at the top. The checkmark follows 0.46 s later, stroke-dashoffset 50 → 0 in 0.3 s, ease-out — the pen-drawing feel is achieved with a single CSS rule, no third-party library.
Two <div> elements stacked inside .scb-svg-wrap produce the pulsing halos: border-radius: 50%; border: 2px solid var(--scb-accent), animated by scb-halo-pulse (opacity 0.68 → 0, scale 1 → 2.7). The first fires at 0.62 s, the second at 0.94 s — the offset creates a double-ring ripple without any JS.
After 100 ms, burst(root) fires the Canvas 2D ring burst: n particles (26 in compact mode, 36 in full mode) arranged in a ring (angle = (i/n)×2π + jitter ±0.1 rad). Each particle gets a radial velocity (80–130 px/s compact, 115–165 px/s full), one of six colors (teal, white, green, yellow, purple, pink), and 32% are 4-point stars drawn on canvas. Physics applies 80 px/s² gravity and per-particle spin. Opacity holds at 1.0 for the first 25% of the 1 200 ms duration, then fades linearly to 0 — the plateau prevents a harsh fade at the animation peak.
Text elements (.scb-title, .scb-amount, .scb-sub, buttons) appear via CSS stagger: each starts at opacity:0; translateY(6px) with a progressive delay (0.76 s to 1.45 s) — no JS for text orchestration. Replay is instant: play() removes .scb-run, forces a reflow via void root.offsetWidth, then re-applies the class to reset all CSS animations.
Accessibility
- prefers-reduced-motion: handled at two levels — CSS (
@media (prefers-reduced-motion: reduce)) kills all animations and shows the checkmark and text instantly; JS checkswindow.matchMediaand exitsburst()before launching the canvas. Zero particles in reduced-motion mode. - The
.scb-rootcarriesrole="status"andaria-live="polite": a screen reader announces the confirmation on replay without interrupting navigation. - The canvas has
aria-hidden="true"— the burst is purely decorative and invisible to assistive technology. - The
.scb-btn-continuebutton (full mode) stays keyboard-focusable; its:focus-visiblestyle uses an accent-colored outline (var(--scb-accent)) withoutline-offset: 2px. - Contrast: white text on card backgrounds
#18181b(compact) and#111116(full) exceeds 16:1 — well above WCAG AA. The CTA uses dark text (--scb-on-accent: #0a0a0f) on teal (#2dd4bf), ≥ 7:1.
Browser compatibility
Requires CSS Animations (stroke-dashoffset), Canvas 2D, and requestAnimationFrame. The SVG circle and checkmark work without canvas — only the particle burst needs Canvas 2D.
Without Canvas 2D, the burst is silently skipped; the SVG circle, checkmark, halos and texts animate normally. Without CSS Animations (IE11), elements stay at their final visible state (final CSS property values are declared outside the animation blocks).
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="scb-root" data-size="compact" data-auto-replay="4000"
role="status" aria-live="polite" aria-label="Animated confirmation toast">
<!-- Particle burst canvas (z=0) -->
<canvas class="scb-canvas" aria-hidden="true"></canvas>
<!-- Visible card (z=2) -->
<div class="scb-scene">
<!-- Icon: SVG wrapper + halos -->
<div class="scb-svg-wrap" aria-hidden="true">
<div class="scb-halo"></div>
<div class="scb-halo"></div>
<svg class="scb-svg" viewBox="0 0 80 80">
<g class="scb-ring-group">
<circle class="scb-ring-track" cx="40" cy="40" r="34"/>
<circle class="scb-ring-draw" cx="40" cy="40" r="34"/>
</g>
<path class="scb-check" d="M24,40 L34,52 L56,28"/>
</svg>
</div>
<!-- Main title -->
<p class="scb-title">Sauvegardé</p>
<!-- Full mode only: amount + subtitle + buttons -->
<!-- <p class="scb-amount">€29.90</p> -->
<!-- <p class="scb-sub">Pro plan activated · Thank you!</p> -->
<!-- <hr class="scb-divider"> -->
<!-- <button class="scb-btn-continue">Continue</button> -->
<!-- <button class="scb-btn-replay">Replay</button> -->
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| --scb-accent | #2dd4bf | Main accent color: SVG ring, halos, focus outline and first particle burst color. Set it on .scb-root to match your brand without touching the JS. |
| data-size="compact" | absent (full mode) | Enables toast mode (n=26 particles, burst speed 80–130 px/s, 180 px min card, 22/28 px padding). Without the attribute: full modal (36 particles, 115–165 px/s, 300 px card, with .scb-amount and .scb-btn-continue). |
| data-auto-replay | absent (no auto) | Interval in ms between automatic replays. data-auto-replay="4000" replays every 4 s — useful for demos or showcases. Omit (or set 0) for a one-shot sequence. |
| root.__scb.play() | — | Public API exposed on each instance: triggers an immediate replay from your own code. Example after a Stripe confirmation on the front end: document.querySelector('.scb-root').__scb.play(). |
| COLORS (JS, var COLORS line) | ['#2dd4bf','#ffffff','#86efac','#fde047','#a78bfa','#f472b6'] | Particle color palette. Edit the array in the copied JS to replace the teal and pastel tones with your brand palette. |
| DUR (JS, var DUR line) | 1200 | Burst duration in milliseconds. Reduce to 800 for a sharp burst, increase to 1800 for a trailing effect. |
| .scb-title (innerHTML) | "Sauvegardé" | Title text displayed in the card — edit the HTML directly: 'Payment confirmed', 'Sign-up complete', etc. |
FAQ
document.querySelectorAll('.scb-root') and attaches an independent __scb API to each instance. Every .scb-root gets its own canvas and animation cycle — they share no global state. Use distinct ids if you need to target a specific element from your JS.DOMContentLoaded and exposes el.__scb.play() on the DOM node. In React, call play() inside a useEffect gated on the business condition (e.g. status === 'success'), not on mount — the component can re-render without triggering a spurious replay. The canvas stays in the DOM and the RAF only runs while .scb-run is present..scb-ring-group applies transform: rotate(-90deg) at transform-origin: 40px 40px (the centre of the 80×80 viewBox). Without this rotation, CSS SVG stroke animation starts at 3 o'clock (angle 0 rad) — the −90° shifts it to the top. The stroke then progresses clockwise until it completes the full circle.