Confetti
Confetti animations are best used to delight your users when something special happens
Confetti
import type { ConfettiRef } from '@/registry/magicui/confetti'import { Confetti } from '@/registry/magicui/confetti'
export function ConfettiDemo() { let confettiRef: ConfettiRef | undefined
return ( <div class=" relative flex h-125 w-full flex-col items-center justify-center overflow-hidden rounded-lg border bg-background " > <span class=" pointer-events-none bg-linear-to-b from-black to-gray-300/80 bg-clip-text text-center text-8xl leading-none font-semibold whitespace-pre-wrap text-transparent dark:from-white dark:to-slate-900/10 " > Confetti </span>
<Confetti ref={(api) => { confettiRef = api }} class="absolute top-0 left-0 z-0 size-full" onMouseEnter={() => { confettiRef?.fire({}) }} /> </div> )}Installation
Section titled “Installation”pnpm dlx shadcn@latest add @magicui-solid/confettibunx shadcn@latest add @magicui-solid/confettiyarn dlx shadcn@latest add @magicui-solid/confettinpx shadcn@latest add @magicui-solid/confettiimport { Confetti, type ConfettiRef } from '@/components/magicui/confetti'
export function ConfettiDemo() { let confettiRef: ConfettiRef | undefined
return ( <div> <Confetti ref={(api) => { confettiRef = api }} manualstart /> <button onClick={() => { confettiRef?.fire() }} > Trigger Confetti </button> </div> )}Examples
Section titled “Examples”Basic Cannon
Section titled “Basic Cannon”import { ConfettiButton } from '@/registry/magicui/confetti'
export function ConfettiBasicCannonDemo() { return ( <div class="relative"> <ConfettiButton>Confetti</ConfettiButton> </div> )}Random Direction
Section titled “Random Direction”import { ConfettiButton } from '@/registry/magicui/confetti'
export function ConfettiRandomDirectionDemo() { return ( <div class="relative"> <ConfettiButton options={{ get angle() { return Math.random() * 360 }, }} > Random Confetti </ConfettiButton> </div> )}Fireworks
Section titled “Fireworks”import confetti from 'canvas-confetti'
import { Button } from '@/components/ui/button'
export function ConfettiFireworksDemo() { const handleClick = () => { const duration = 5 * 1000 const animationEnd = Date.now() + duration const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }
const randomInRange = (min: number, max: number) => Math.random() * (max - min) + min
const interval = window.setInterval(() => { const timeLeft = animationEnd - Date.now()
if (timeLeft <= 0) { clearInterval(interval) return }
const particleCount = 50 * (timeLeft / duration) void confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 }, }) void confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 }, }) }, 250) }
return ( <div class="relative"> <Button onClick={handleClick}>Trigger Fireworks</Button> </div> )}Side Cannons
Section titled “Side Cannons”import confetti from 'canvas-confetti'
import { Button } from '@/components/ui/button'
export function ConfettiSideCannonsDemo() { const handleClick = () => { const end = Date.now() + 3 * 1000 const colors = ['#a786ff', '#fd8bbc', '#eca184', '#f8deb1']
const frame = () => { if (Date.now() > end) return
void confetti({ particleCount: 2, angle: 60, spread: 55, startVelocity: 60, origin: { x: 0, y: 0.5 }, colors, }) void confetti({ particleCount: 2, angle: 120, spread: 55, startVelocity: 60, origin: { x: 1, y: 0.5 }, colors, })
requestAnimationFrame(frame) }
frame() }
return ( <div class="relative"> <Button onClick={handleClick}>Trigger Side Cannons</Button> </div> )}import confetti from 'canvas-confetti'
import { Button } from '@/components/ui/button'
export function ConfettiStarsDemo() { const handleClick = () => { const defaults = { spread: 360, ticks: 50, gravity: 0, decay: 0.94, startVelocity: 30, colors: ['#FFE400', '#FFBD00', '#E89400', '#FFCA6C', '#FDFFB8'], }
const shoot = () => { void confetti({ ...defaults, particleCount: 40, scalar: 1.2, shapes: ['star'], })
void confetti({ ...defaults, particleCount: 10, scalar: 0.75, shapes: ['circle'], }) }
setTimeout(shoot, 0) setTimeout(shoot, 100) setTimeout(shoot, 200) }
return ( <div class="relative"> <Button onClick={handleClick}>Trigger Stars</Button> </div> )}Custom Shapes
Section titled “Custom Shapes”import confetti from 'canvas-confetti'
import { Button } from '@/components/ui/button'
export function ConfettiCustomShapesDemo() { const handleClick = () => { const scalar = 2 const triangle = confetti.shapeFromPath({ path: 'M0 10 L5 0 L10 10z', }) const square = confetti.shapeFromPath({ path: 'M0 0 L10 0 L10 10 L0 10 Z', }) const coin = confetti.shapeFromPath({ path: 'M5 0 A5 5 0 1 0 5 10 A5 5 0 1 0 5 0 Z', }) const tree = confetti.shapeFromPath({ path: 'M5 0 L10 10 L0 10 Z', })
const defaults = { spread: 360, ticks: 60, gravity: 0, decay: 0.96, startVelocity: 20, shapes: [triangle, square, coin, tree], scalar, }
const shoot = () => { void confetti({ ...defaults, particleCount: 30, })
void confetti({ ...defaults, particleCount: 5, })
void confetti({ ...defaults, particleCount: 15, scalar: scalar / 2, shapes: ['circle'], }) }
setTimeout(shoot, 0) setTimeout(shoot, 100) setTimeout(shoot, 200) }
return ( <div class="relative flex items-center justify-center"> <Button onClick={handleClick}>Trigger Shapes</Button> </div> )}import confetti from 'canvas-confetti'
import { Button } from '@/components/ui/button'
export function ConfettiEmojiDemo() { const handleClick = () => { const scalar = 2 const unicorn = confetti.shapeFromText({ text: '🦄', scalar })
const defaults = { spread: 360, ticks: 60, gravity: 0, decay: 0.96, startVelocity: 20, shapes: [unicorn], scalar, }
const shoot = () => { void confetti({ ...defaults, particleCount: 30, })
void confetti({ ...defaults, particleCount: 5, })
void confetti({ ...defaults, particleCount: 15, scalar: scalar / 2, shapes: ['circle'], }) }
setTimeout(shoot, 0) setTimeout(shoot, 100) setTimeout(shoot, 200) }
return ( <div class="relative justify-center"> <Button onClick={handleClick}>Trigger Emoji</Button> </div> )}Confetti
Section titled “Confetti”| Prop | Type | Default | Description |
|---|---|---|---|
ref |
(api: ConfettiRef) => void |
- |
Callback exposing an imperative fire(options?: ConfettiOptions) method |
options |
ConfettiOptions |
{} |
Default options for automatic or imperative confetti triggers |
globalOptions |
ConfettiGlobalOptions |
{ resize: true, useWorker: true } |
Global options passed to canvas-confetti.create() |
manualstart |
Boolean |
false |
Prevents automatic confetti firing on component mount |
class |
String |
undefined |
Custom CSS classes applied to the canvas element |
ConfettiRef
Section titled “ConfettiRef”| Method | Parameters | Return Type | Description |
|---|---|---|---|
fire |
options?: ConfettiOptions |
Promise<void> / void |
Imperatively triggers a confetti burst on the canvas instance |
ConfettiOptions
Section titled “ConfettiOptions”| Field | Type | Default | Description |
|---|---|---|---|
particleCount |
Integer |
50 |
Number of confetti particles to launch |
angle |
Number |
90 |
Launch angle in degrees |
spread |
Number |
45 |
Spread angle in degrees |
startVelocity |
Number |
45 |
Initial particle velocity |
decay |
Number |
0.9 |
Velocity decay rate |
gravity |
Number |
1 |
Gravity applied to particles |
drift |
Number |
0 |
Horizontal drift factor |
flat |
Boolean |
false |
Renders flat 2D shapes |
ticks |
Number |
200 |
Number of animation frames confetti lasts |
origin |
{ x: number, y: number } |
{ x: 0.5, y: 0.5 } |
Normalized viewport origin coordinates (0.0 to 1.0) |
colors |
Array of Strings |
HEX array |
Custom HEX color palette |
shapes |
Array of Strings |
['square', 'circle', 'star'] |
Particle shapes or custom text shapes |
zIndex |
Integer |
9999 |
Z-index of the confetti burst |
scalar |
Number |
1 |
Scaling factor for particle dimensions |
ConfettiButton
Section titled “ConfettiButton”| Prop | Type | Default | Description |
|---|---|---|---|
options |
ConfettiOptions & ConfettiGlobalOptions |
{} |
Options for the confetti launched on button click |
children |
JSX.Element |
null |
Button label and child elements |
Credits
Section titled “Credits”- Credit to Bankk
- Inspired by canvas-confetti
Original:
magicui.design/docs/components/confetti