How to Make a Confetti Explosion Using JavaScript

Ever feel like your website needs a little more… party? Whether a user just signed up, finished a task, or simply clicked a Celebrate button, a burst of confetti is a classic way to add a touch of delight.
Today, we’re going to build a lightweight, high-performance confetti explosion using the HTML5 Canvas API. No bulky external libraries are required—just a single script and a dream.
See Confetti in Action
How the Confetti Javascript Works
The script works by dynamically creating a <canvas> element that covers your entire screen. When you click an element with the class .confetti, the script calculates the center of that element and spawns 150 unique particles.
Each particle has its own:
- Physics: Velocity, gravity, and drag are applied every frame.
- Aesthetics: Randomized colors from a curated palette and varying sizes.
- Movement: A spin factor and rotation to make it look like real paper fluttering.
- Lifecycle: An opacity decay that makes the particles fade out before they are removed from memory.
The JavaScript
You can drop this script into your project.
<script src="confetti.js"></script> It’s wrapped in an IIFE (Immediately Invoked Function Expression) to keep the global namespace clean.
(function () {
const PARTICLE_COUNT = 150;
const COLORS = [
'#ff0a54', '#ff477e', '#ff7096', '#ff85a1',
'#fbb1bd', '#f9bec7', '#3a86ff', '#8338ec',
'#ffbe0b', '#fb5607', '#06d6a0', '#118ab2',
];
const GRAVITY = 0.12;
const DRAG = 0.98;
const SPIN_DRAG = 0.97;
let canvas, ctx, particles, animId;
function createCanvas() {
canvas = document.createElement('canvas');
// Set styles to cover the viewport and ignore mouse events
canvas.style.cssText =
'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:2147483647';
document.body.appendChild(canvas);
ctx = canvas.getContext('2d');
resize();
window.addEventListener('resize', resize);
}
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function randomBetween(a, b) {
return a + Math.random() * (b - a);
}
function createParticle(x, y) {
const angle = randomBetween(0, 2 * Math.PI);
const speed = randomBetween(6, 18);
return {
x: x,
y: y,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed - randomBetween(2, 8),
w: randomBetween(6, 12),
h: randomBetween(4, 8),
color: COLORS[Math.floor(Math.random() * COLORS.length)],
rotation: randomBetween(0, 2 * Math.PI),
spin: randomBetween(-0.3, 0.3),
opacity: 1,
decay: randomBetween(0.006, 0.012),
};
}
function explode(originX, originY) {
if (!canvas) createCanvas();
// Restart animation if one is already running
if (animId) cancelAnimationFrame(animId);
particles = [];
for (let i = 0; i < PARTICLE_COUNT; i++) {
particles.push(createParticle(originX, originY));
}
animate();
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
// Physics logic
p.vx *= DRAG;
p.vy *= DRAG;
p.vy += GRAVITY;
p.x += p.vx;
p.y += p.vy;
p.rotation += p.spin;
p.spin *= SPIN_DRAG;
p.opacity -= p.decay;
if (p.opacity <= 0) {
particles.splice(i, 1);
continue;
}
// Drawing logic
ctx.save();
ctx.translate(p.x, p.y);
ctx.rotate(p.rotation);
ctx.globalAlpha = p.opacity;
ctx.fillStyle = p.color;
ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
ctx.restore();
}
if (particles.length > 0) {
animId = requestAnimationFrame(animate);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height);
animId = null;
}
}
// Global Click Listener
document.addEventListener('click', function (e) {
const trigger = e.target.closest('.confetti');
if (!trigger) return;
const rect = trigger.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
explode(cx, cy);
});
})(); Implementation Guide
- Add the Script: Copy the code above into a
.jsfile and link it at the end of your<body>, or wrap it in<script>tags directly in your HTML. - Tag Your Trigger: You don’t need to write any extra JavaScript for the buttons. Simply add the class
confettito any button, link, or div you want:<button class="confetti">Click Me!</button> - Customize:
- Want more confetti? Change
PARTICLE_COUNT. - Want a different vibe? Update the
COLORSarray with your brand’s hex codes. - Want floatier confetti? Decrease the
GRAVITYvalue.
- Want more confetti? Change
Happy celebrating! 🥳







