Skip to content

Confetti

import { Confetti, confetti } from '@delightstack/components';

The confetti function and Confetti component can be imported together. Types are also available:

import type { ConfettiOptions, ConfettiTarget, CannonOptions, RainOptions } from '@delightstack/components';

The simplest way to fire confetti is with the confetti() function. No component mounting required.

burst and cannon are local effects — they erupt from a point. By default that point is wherever the user last clicked, so a confetti() fired from a click handler looks like it bursts out of the button that was pressed, with no extra code. fireworks, sides, and rain are global effects that fill the viewport and ignore the origin. See Targeting Local Effects to anchor a burst to a specific element instead.

View code
<script>
import { confetti } from '@delightstack/components';
import { Button } from '@delightstack/components';
</script>
<Button onclick={() => confetti()}>Burst</Button>
<Button outline onclick={() => confetti.fireworks()}>Fireworks</Button>
<Button outline onclick={() => confetti.sides()}>Sides</Button>

Mount <Confetti /> and control it with the active prop.

View code
<script>
import { Confetti } from '@delightstack/components';
let celebrating = $state(false);
</script>
<button onclick={() => celebrating = true}>Celebrate!</button>
<Confetti active={celebrating} onend={() => celebrating = false} />
View code
<script>
import { confetti } from '@delightstack/components';
function celebrate() {
confetti({
particle_count: 100,
spread: 70,
origin: { x: 0.5, y: 0.6 },
colors: ['#ff0000', '#00ff00', '#0000ff'],
});
}
</script>
<button onclick={celebrate}>Custom Burst</button>

All presets are available as methods on the confetti function.

View code
<script>
import { confetti } from '@delightstack/components';
</script>
<!-- Single burst (same as confetti()) -->
<button onclick={() => confetti.burst()}>Burst</button>
<!-- Continuous cannon stream -->
<button onclick={() => confetti.cannon({ duration: 3000 })}>Cannon</button>
<!-- Multiple random bursts -->
<button onclick={() => confetti.fireworks()}>Fireworks</button>
<!-- Bursts from both screen edges -->
<button onclick={() => confetti.sides()}>Sides</button>
<!-- Gentle particles falling from top -->
<button onclick={() => confetti.rain({ duration: 4000 })}>Rain</button>

confetti.cannon() and confetti.rain() return a stop() function. You can also use confetti.stop() to stop all active animations.

View code
<script>
import { confetti } from '@delightstack/components';
let stopCannon: (() => void) | undefined;
function startCannon() {
stopCannon = confetti.cannon({ duration: 10000 });
}
</script>
<button onclick={startCannon}>Start Cannon</button>
<button onclick={() => stopCannon?.()}>Stop Cannon</button>
<button onclick={() => confetti.stop()}>Stop All</button>
View code
<script>
import { Confetti } from '@delightstack/components';
let celebrating = $state(false);
</script>
<button onclick={() => celebrating = true}>Complete Task</button>
<Confetti
active={celebrating}
preset="cannon"
duration={2000}
onend={() => celebrating = false}
/>

Local effects (burst, cannon) erupt from the last clicked point automatically, so the first button below needs no configuration. To anchor a burst somewhere else, pass a target — a DOM element, a CSS selector, or a pointer/mouse event. It takes precedence over the last click and over origin.

View code
<script>
import { confetti } from '@delightstack/components';
let box;
</script>
<!-- Auto-targets the click -->
<button onclick={() => confetti.burst()}>Burst from me</button>
<!-- Explicit target: an element ref (a selector string or event also work) -->
<button onclick={() => confetti.burst({ target: box })}>Burst from the box</button>
<div bind:this={box}></div>

Fire a single burst of confetti. Shorthand for confetti.burst().

Single explosion. A local effect: it erupts from target, then origin, then the last clicked point, falling back to bottom-center.

Continuous stream of particles from a single point. A local effect that honors target/origin just like burst. Returns a stop() function.

Multiple large timed bursts from random positions across the viewport. A global effect; ignores target/origin.

Simultaneous bursts from both screen edges, angled inward. A global effect; ignores target/origin.

Gentle particles falling from the top. Returns a stop() function.

Stop all active animations and clean up the canvas.

Component props for <Confetti />. The defaults below apply to the burst preset; any prop left unset falls back to the chosen preset’s own default (for example, fireworks uses a larger particle_count).

PropTypeDefaultDescription
activebooleanfalseTrigger confetti when set to true
preset'burst' | 'cannon' | 'fireworks' | 'sides' | 'rain''burst'Animation preset
particle_countnumber50Number of particles (max 500)
spreadnumber60Spread angle in degrees
start_velocitynumber30Initial launch speed
decaynumber0.94Velocity decay per frame (0-1)
gravitynumber1Gravity multiplier
driftnumber0Horizontal drift
ticksnumber200Frames before particle fades
origin{ x: number, y: number }last clickOrigin point for local effects (0-1 normalized)
targetConfettiTargetAnchor a local effect to an element, selector, or event
colorsstring[]Rainbow paletteParticle color palette
scalarnumber1Particle size multiplier
z_indexnumber1000Canvas z-index
durationnumber3000Duration for cannon/rain presets (ms)
disable_for_reduced_motionbooleantrueRespect prefers-reduced-motion
idstringautoElement ID
classstring''Additional CSS classes
EventDetailDescription
onend() => voidCalled when all particles have finished animating
// Anchor for a local effect: an element, a CSS selector, or a pointer/mouse event
type ConfettiTarget = Element | string | MouseEvent;
interface ConfettiOptions {
particle_count?: number;
spread?: number;
start_velocity?: number;
decay?: number;
gravity?: number;
drift?: number;
ticks?: number;
origin?: { x: number; y: number };
target?: ConfettiTarget;
colors?: string[];
scalar?: number;
z_index?: number;
angle?: number;
}
interface CannonOptions extends ConfettiOptions {
interval?: number;
duration?: number;
}
interface RainOptions extends ConfettiOptions {
duration?: number;
}
  • Canvas element has aria-hidden="true" (purely decorative)
  • pointer-events: none on the canvas so it never blocks interaction
  • Respects prefers-reduced-motion by default — when active, confetti() is a no-op
  • No sound effects or other sensory output