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.