konfetti
Confetti for the web that behaves like paper: pieces tumble, catch the light and float down. One function call, zero dependencies, about 5 kB gzipped. Works on its own or with React, Vue, Svelte, Solid and Web Components.
npm install @konfetti-js/core
Click or tap anywhere in this top section to fire from that spot.
Your system asks for reduced motion, so konfetti.js skips animations by default.
That is the disableForReducedMotion option at work.
Playground
Try a preset, or tune the options and fire your own. The code updates as you go, ready to paste.
Install and use
The core package does the work. Each framework package is a thin wrapper that
installs core for you. Coming from the konfetti.js package? Follow the
migration guide.
npm install @konfetti-js/core
import { fire, cannon, continuous } from '@konfetti-js/core';
// A burst from the middle of the screen
fire();
// Tune it
fire({ particleCount: 120, spread: 70, origin: { x: 0.5, y: 0.8 } });
// Use a preset, and override any of its options
cannon({ colors: ['#ff48b0', '#0078bf'] });
// A steady stream; call the returned function to stop it
const stop = continuous();
setTimeout(stop, 3000);
No build step needed. The browser bundle puts everything on window.konfetti.
<script src="https://cdn.jsdelivr.net/npm/@konfetti-js/core@0.4/dist/konfetti.min.js"></script>
<script>
konfetti.fire({ particleCount: 100 });
</script>
Or import the ES module directly:
<script type="module">
import { fireworks } from 'https://cdn.jsdelivr.net/npm/@konfetti-js/core@0.4/+esm';
fireworks();
</script>
npm install @konfetti-js/react
import { useState } from 'react';
import { useKonfetti, Konfetti } from '@konfetti-js/react';
// Hook: call the functions from your own handlers
function SaveButton() {
const { cannon } = useKonfetti();
return <button onClick={() => cannon()}>Save</button>;
}
// Component: fires when `fire` turns true
function Celebration() {
const [done, setDone] = useState(false);
return (
<>
<button onClick={() => setDone(true)}>Finish</button>
<Konfetti fire={done} preset="fireworks" onFired={() => setDone(false)} />
</>
);
}
npm install @konfetti-js/vue
<script setup>
import { useKonfetti, vKonfetti } from '@konfetti-js/vue';
const { fire } = useKonfetti();
</script>
<template>
<!-- Composable -->
<button @click="fire({ particleCount: 100 })">Celebrate</button>
<!-- Directive: fires from the element on click -->
<button v-konfetti>Click me</button>
<button v-konfetti="{ preset: 'fireworks' }">Fireworks</button>
</template>
npm install @konfetti-js/svelte
<script>
import { konfettiAction, createKonfetti } from '@konfetti-js/svelte';
const { fire } = createKonfetti();
</script>
<!-- Action: fires from the element on click -->
<button use:konfettiAction>Click me</button>
<button use:konfettiAction={{ preset: 'fireworks' }}>Fireworks</button>
<!-- Functions -->
<button onclick={() => fire()}>Celebrate</button>
npm install @konfetti-js/solid
import { createSignal } from 'solid-js';
import { useKonfetti, Konfetti } from '@konfetti-js/solid';
function SaveButton() {
const { cannon } = useKonfetti();
return <button onClick={() => cannon()}>Save</button>;
}
function Celebration() {
const [done, setDone] = createSignal(false);
return (
<>
<button onClick={() => setDone(true)}>Finish</button>
<Konfetti fire={done()} preset="fireworks" onFired={() => setDone(false)} />
</>
);
}
npm install @konfetti-js/web-components
<script type="module">
import { defineAllElements } from '@konfetti-js/web-components';
defineAllElements();
</script>
<!-- Fires when anything inside is clicked -->
<konfetti-trigger preset="fireworks">
<button>Click me</button>
</konfetti-trigger>
<!-- Fire it from your own code -->
<konfetti-burst id="burst" preset="cannon"></konfetti-burst>
<script>
document.getElementById('burst').fire();
</script>
API
fire(options?)
Fires one burst on a full-screen canvas that is created on first use and sits above your page without blocking clicks. Each piece is a little sheet of paper: it tumbles in 3D, gets lighter and darker as it turns, slows down in the air and sways on its way down. Every option is optional.
| Option | Default | What it does |
|---|---|---|
particleCount | 50 | How many pieces to fire. |
angle | 90 | Launch direction in degrees. 90 is straight up, 0 is right. |
spread | 45 | How far pieces fan out from the angle, in degrees. 360 fires in every direction. |
startVelocity | 45 | Launch speed. |
decay | 0.9 | Air resistance: how quickly pieces slow down. Lower values stop them sooner. |
gravity | 1 | How strongly pieces fall. 0 lets them float. |
drift | 0 | Wind. Negative blows left, positive blows right. |
ticks | 600 | Longest a piece may live, in frames at 60 fps (600 is 10 seconds). Pieces disappear once they leave the screen, which usually comes first. |
origin | { x: 0.5, y: 0.5 } | Where pieces start, from 0 to 1 across and down the viewport. |
colors | seven bright colors | List of CSS colors such as '#ff48b0' or 'gold'. |
shapes | ['circle', 'square'] | Which shapes to draw. |
scalar | 1 | Size multiplier for every piece. |
zIndex | 100 | Stacking order of the canvas. |
disableForReducedMotion | true | Skip the animation when the visitor has asked their system for reduced motion. |
Presets
Ready-made effects. Each takes the same options as fire, and anything
you pass overrides the preset’s own values. To pick one by name, use
firePreset('snow', options).
cannon()- A burst shooting up from the bottom of the screen.
explosion()- A burst in every direction from the center.
fireworks()- Three quick bursts across the top half.
rain()- Pieces falling from the top.
snow()- Slow white flakes drifting down.
sideCannons()- Two bursts aimed in from the left and right edges.
pride()- A burst in rainbow colors.
continuous(options?, interval?)- A steady stream, one small burst every
intervalmilliseconds (250 by default). Returns a function that stops it.
fireFromElement(element, options?)
Fires from the center of an element, such as the button that was just clicked. Add
preset to the options to fire a preset instead. Single bursts like
cannon start at the element; screen-wide presets like
fireworks keep their own positions.
import { fireFromElement } from '@konfetti-js/core';
button.addEventListener('click', () => {
fireFromElement(button, { preset: 'explosion', particleCount: 60 });
});
reset() and destroy()
reset() clears every piece from the screen and cancels bursts and
streams that are still scheduled. destroy() also removes the canvas;
the next fire() creates a new one.
create(canvas, options?)
Draws into a canvas you provide instead of the full-screen one, for example to
keep confetti inside a card. Returns a fire function that also has
preset(), continuous(), reset() and
destroy(). Pass
{ resize: false } to stop it from following window resizes.
import { create } from '@konfetti-js/core';
const burst = create(document.querySelector('#card-canvas'));
burst({ particleCount: 80, origin: { x: 0.5, y: 1 } });
burst.preset('pride');
// When the card goes away
burst.destroy();
Accessibility
konfetti.js respects prefers-reduced-motion. When a visitor has asked
for reduced motion, nothing animates unless you pass
disableForReducedMotion: false. The canvas is hidden from assistive
technology and ignores pointer events, so it never gets in the way of your page.