Skip to content

Success Check

A copy-paste confetti & celebration component in pure HTML, CSS & vanilla JS. Zero dependencies, framework-agnostic, MIT-licensed.

Confetti & CelebrationHTMLCSSJavaScriptany framework

Copy into your project

HTML
<button class="nuda-confetti-check" aria-label="Confirm success">
  <svg class="nuda-confetti-check__ring" viewBox="0 0 52 52" aria-hidden="true">
    <circle class="nuda-confetti-check__circle" cx="26" cy="26" r="24" fill="none"/>
    <path class="nuda-confetti-check__path" fill="none" d="M14 27l8 8 16-18"/>
  </svg>
  <span class="nuda-confetti-check__pieces" aria-hidden="true">
    <span class="nuda-confetti-check__piece" style="--a:0deg;   --c:#e4ff54"></span>
    <span class="nuda-confetti-check__piece" style="--a:36deg;  --c:#ff5db1"></span>
    <span class="nuda-confetti-check__piece" style="--a:72deg;  --c:#5dd0ff"></span>
    <span class="nuda-confetti-check__piece" style="--a:108deg; --c:#e4ff54"></span>
    <span class="nuda-confetti-check__piece" style="--a:144deg; --c:#ff5db1"></span>
    <span class="nuda-confetti-check__piece" style="--a:180deg; --c:#5dd0ff"></span>
    <span class="nuda-confetti-check__piece" style="--a:216deg; --c:#e4ff54"></span>
    <span class="nuda-confetti-check__piece" style="--a:252deg; --c:#ff5db1"></span>
    <span class="nuda-confetti-check__piece" style="--a:288deg; --c:#5dd0ff"></span>
    <span class="nuda-confetti-check__piece" style="--a:324deg; --c:#e4ff54"></span>
  </span>
</button>
CSS
/* Success Check
   Checkmark draws inside a ring, then a confetti burst fires.
   Customize: --confetti-check-color. */

.nuda-confetti-check {
  --confetti-check-color: #22c55e;
  position: relative;
  width: 60px;
  height: 60px;
  background: none;
  border: none;
  padding: 4px;
  cursor: pointer;
  outline: none;
  color: var(--confetti-check-color);
}

.nuda-confetti-check:focus-visible {
  box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.4);
  border-radius: 50%;
}

.nuda-confetti-check__ring { width: 52px; height: 52px; }

.nuda-confetti-check__circle {
  stroke: var(--confetti-check-color);
  stroke-width: 3;
  stroke-dasharray: 151;
  stroke-dashoffset: 0;
}

.nuda-confetti-check__path {
  stroke: var(--confetti-check-color);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 48;
  stroke-dashoffset: 0;
}

.nuda-confetti-check--go .nuda-confetti-check__circle {
  animation: nuda-confetti-check-ring 0.5s ease-out forwards;
}

.nuda-confetti-check--go .nuda-confetti-check__path {
  animation: nuda-confetti-check-draw 0.4s 0.35s ease-out backwards;
}

.nuda-confetti-check__pieces {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.nuda-confetti-check__piece {
  position: absolute;
  width: 6px;
  height: 6px;
  border-radius: 1px;
  background: var(--c, #e4ff54);
  opacity: 0;
  transform: rotate(var(--a, 0deg)) translateY(0) scale(0.4);
  will-change: transform, opacity;
}

.nuda-confetti-check--go .nuda-confetti-check__piece {
  animation: nuda-confetti-check-fly 0.7s 0.4s cubic-bezier(0.2, 0.6, 0.4, 1) forwards;
}

@keyframes nuda-confetti-check-ring {
  0%   { stroke-dashoffset: 151; }
  100% { stroke-dashoffset: 0; }
}

@keyframes nuda-confetti-check-draw {
  0%   { stroke-dashoffset: 48; }
  100% { stroke-dashoffset: 0; }
}

@keyframes nuda-confetti-check-fly {
  0%   { opacity: 0; transform: rotate(var(--a)) translateY(0) scale(0.4); }
  20%  { opacity: 1; }
  100% { opacity: 0; transform: rotate(var(--a)) translateY(-40px) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .nuda-confetti-check--go .nuda-confetti-check__circle,
  .nuda-confetti-check--go .nuda-confetti-check__path,
  .nuda-confetti-check--go .nuda-confetti-check__piece { animation: none; }
  .nuda-confetti-check__piece { opacity: 0; }
}
JavaScript
/* Success Check — vanilla JS
   Re-runs the checkmark draw + confetti burst on each click. */

(function () {
  document.querySelectorAll(".nuda-confetti-check").forEach(function (btn) {
    btn.addEventListener("click", function () {
      btn.classList.remove("nuda-confetti-check--go");
      void btn.offsetWidth;
      btn.classList.add("nuda-confetti-check--go");
      setTimeout(function () {
        btn.classList.remove("nuda-confetti-check--go");
      }, 1200);
    });
  });
})();

How to use Success Check

Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.

Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.

More confetti & celebration components

← Browse all NudaUI components