Back to Dictionary
Status & Confirmation
●●●Requires Setup
AdvancedConfetti Burst
A joyful explosion of colorful particles from the center or edges of the screen to celebrate a major user milestone.
Use
Completing onboarding
Avoid
Routine, frequent actions
Safer Alternative
No safer default listed.
Risk Level
Low risk
Live Demo
Goal Achieved!
You've successfully completed all your assigned tasks for the day.
What It Is
A joyful explosion of colorful particles from the center or edges of the screen to celebrate a major user milestone.
✓When to Use
- Completing onboarding
- Reaching inbox zero
- Making a first sale
✕When NOT to Use
- Routine, frequent actions
Configuration Tips
- 01Use a specialized library like canvas-confetti for performant particle physics
- 02Trigger immediately upon the success state rendering
You've Seen It In
Linear (Inbox Zero)Stripe (1st Payment)Mailchimp (Sent)
AI Implementation Prompts
Move from a fast scaffold to production details, then tune timing and edge states.
Add a celebration confetti burst that shoots from the bottom of the screen when I click complete.
Reference Implementation
The same implementation approach used by the live preview, kept compact enough to inspect and adapt.
"use client";
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Trophy } from 'lucide-react';
export function ConfettiBurstDemo({ isPlaying = false }: { isPlaying?: boolean }) {
const [isExploding, setIsExploding] = useState(false);
useEffect(() => {
if (!isPlaying) {
setIsExploding(false);
return;
}
triggerConfetti();
const interval = setInterval(() => {
triggerConfetti();
}, 3500);
return () => clearInterval(interval);
}, [isPlaying]);
const triggerConfetti = () => {
setIsExploding(true);
setTimeout(() => setIsExploding(false), 2000);
};
"text-stone-400 italic">// Generate confetti pieces
const pieces = Array.from({ length: 60 }).map((_, i) => ({
id: i,
x: (Math.random() - 0.5) * 500, "text-stone-400 italic">// random spread
y: (Math.random() - 0.5) * 500 - 150, "text-stone-400 italic">// mostly upwards
rotation: Math.random() * 360,
scale: Math.random() * 0.6 + 0.4,
color: ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6', '#ec4899', '#06b6d4'][Math.floor(Math.random() * 7)]
}));
return (
<div className="relative flex h-64 w-full items-center justify-center overflow-hidden rounded-2xl bg-stone-50 p-6 shadow-sm ring-1 ring-stone-200">
<div className="flex flex-col items-center z-10 bg-white/50 backdrop-blur p-8 rounded-3xl shadow-sm border border-stone-200">
<div className="w-20 h-20 bg-yellow-100 rounded-full flex items-center justify-center mb-6 shadow-inner border-[4px] border-white">
<Trophy className="w-10 h-10 text-yellow-500 drop-shadow-sm" />
</div>
<h3 className="text-2xl font-bold text-stone-900 mb-2">Goal Achieved!</h3>
<p className="text-stone-500 mb-8 max-w-[250px] text-center text-sm">
You've successfully completed all your assigned tasks for the day.
</p>
<button
onClick={triggerConfetti}
className="px-8 py-3.5 bg-stone-900 text-white rounded-2xl font-medium shadow-md hover:bg-stone-800 transition-colors active:scale-95 outline-none focus:ring-4 focus:ring-stone-200"
>
Celebrate
</button>
</div>
{"text-stone-400 italic">/* Confetti container */}
<AnimatePresence>
{isExploding && (
<div className="absolute inset-0 pointer-events-none flex items-center justify-center z-20">
{pieces.map((piece) => (
<motion.div
key={piece.id}
initial={{ x: 0, y: 0, scale: 0, rotate: 0, opacity: 1 }}
animate={{
x: piece.x,
y: piece.y,
scale: piece.scale,
rotate: piece.rotation + 360 * (Math.random() > 0.5 ? 1 : -1),
opacity: [1, 1, 0] "text-stone-400 italic">// fade out at the end
}}
exit={{ opacity: 0 }}
transition={{
duration: 1.5 + Math.random() * 1.5,
ease: "easeOut",
opacity: { duration: 2.5, times: [0, 0.7, 1] }
}}
className="absolute w-3 h-3 rounded-[2px]"
style={{ backgroundColor: piece.color }}
/>
))}
</div>
)}
</AnimatePresence>
</div>
);
}