Subscribe Confetti
The border fills upward with a purple gradient, the label swaps to a checkmark, then twenty-four confetti pieces in six colors burst outward in a celebratory fan.
Subscribe Confetti the 6th of 43 designs in the 43 CSS Button Designs collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
The code
<button class="btn-sub"> <span class="btn-sub-fill" aria-hidden="true"></span> <span class="btn-sub-text">Subscribe Now</span> <span class="btn-sub-check">✦ Subscribed!</span> </button>
.btn-sub {
position: relative;
min-width: 180px;
padding: 14px 30px;
border: 2px solid #7c3aed;
border-radius: 12px;
background: transparent;
color: #7c3aed;
font-family: ui-sans-serif, system-ui, sans-serif;
font-size: 13px;
font-weight: 600;
cursor: pointer;
overflow: hidden;
user-select: none;
transition: transform 0.2s;
}
.btn-sub-fill {
position: absolute;
inset: 0;
z-index: 0;
background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);
transform: scaleY(0);
transform-origin: bottom;
transition: transform 0.4s cubic-bezier(.77,0,.18,1);
}
.btn-sub-text {
position: relative;
z-index: 1;
transition: color 0.2s 0.15s, opacity 0.2s;
}
.btn-sub-check {
position: absolute;
inset: 0;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
color: #fff;
font-size: 13px;
font-weight: 600;
opacity: 0;
transform: translateY(12px);
transition: opacity 0.3s 0.2s, transform 0.3s 0.2s;
}
.btn-sub.is-subscribed { pointer-events: none; transform: scale(0.98); }
.btn-sub.is-subscribed .btn-sub-fill { transform: scaleY(1); }
.btn-sub.is-subscribed .btn-sub-text { opacity: 0; color: #fff; }
.btn-sub.is-subscribed .btn-sub-check { opacity: 1; transform: translateY(0); }
.btn-sub-confetti {
position: absolute;
width: var(--w, 6px);
height: var(--h, 8px);
background: var(--c, #7c3aed);
pointer-events: none;
z-index: 20;
animation: btn-sub-fall 0.9s cubic-bezier(.22,1,.36,1) forwards;
}
@keyframes btn-sub-fall {
0% { transform: translate(0,0) rotate(0deg) scale(1); opacity: 1; }
100% { transform: translate(var(--tx), var(--ty)) rotate(var(--r)) scale(0.5); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.btn-sub-fill, .btn-sub-text, .btn-sub-check { transition: none; }
.btn-sub-confetti { animation: none; }
} document.querySelectorAll('.btn-sub').forEach(function (btn) {
var done = false;
var colors = ['#7c3aed', '#a855f7', '#ec4899', '#f59e0b', '#10b981', '#3b82f6'];
btn.addEventListener('click', function () {
if (done) return;
done = true;
btn.classList.add('is-subscribed');
var w = btn.offsetWidth;
var h = btn.offsetHeight;
for (var i = 0; i < 24; i++) {
var p = document.createElement('span');
p.className = 'btn-sub-confetti';
var angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI * 1.6;
var dist = 40 + Math.random() * 70;
p.style.left = (w / 2 + (Math.random() - 0.5) * w * 0.6) + 'px';
p.style.top = (h / 2) + 'px';
p.style.setProperty('--w', (4 + Math.random() * 6) + 'px');
p.style.setProperty('--h', (5 + Math.random() * 9) + 'px');
p.style.setProperty('--c', colors[Math.floor(Math.random() * colors.length)]);
p.style.setProperty('--tx', (Math.cos(angle) * dist) + 'px');
p.style.setProperty('--ty', (Math.sin(angle) * dist) + 'px');
p.style.setProperty('--r', (Math.random() * 360 - 180) + 'deg');
p.style.animationDelay = (Math.random() * 0.15) + 's';
p.style.borderRadius = Math.random() > 0.5 ? '50%' : '2px';
btn.appendChild(p);
p.addEventListener('animationend', function () { this.remove(); });
}
});
});