mrkeyoor.com_
Tue 22 Sept 18:52 UTC
npmWeb Frontendupdated 22 Sept 2026

canvas-confetti review

canvas-confetti draws temporary particle bursts in a browser canvas, with controls for origin, direction, spread, velocity, gravity, lifetime, color, and shape. It can use its own full-page canvas or one supplied by the application. The 1.9.4 release fixes an OffscreenCanvas capability check that could throw when the global existed but bitmap drawing did not work. In our package check, the browser import came to 10.6 KB minified and 4.3 KB gzipped, while the installed package had no direct dependencies and no TypeScript declarations.

Verdict

Our canvas-confetti 1.9.4 install took 0.8 seconds, occupied 1 MB, and produced a 4.3 KB gzipped browser import with no audit findings. Install it for a finite browser celebration; choose a particle engine for persistent scenes, and set reduced-motion behavior before release.

We installed it

Lab card: what happened when we installed canvas-confettiScreenshot of canvas-confetti documentation
Install✓ · 0.8s1 package on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browser4.3 KBgzipped (10.6 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does canvas-confetti install cleanly?

Yes. In a fresh container with an empty cache, npm install canvas-confetti finished in 0.8s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does canvas-confetti add to a browser bundle?

4.3 KB gzipped (10.6 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does canvas-confetti work with both ESM and CommonJS?

Yes. Both import 'canvas-confetti' and require('canvas-confetti') worked in Node 22 in our run. The package is published as CommonJS.

Does canvas-confetti include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

canvas-confetti or js-confetti: which should you use?

js-confetti: Use it when a class-based API and emoji confetti cover the whole job. Our canvas-confetti 1.9.4 install took 0.8 seconds, occupied 1 MB, and produced a 4.3 KB gzipped browser import with no audit findings.

When should you not use canvas-confetti?

The animation must run during server rendering or inside Node; the project describes canvas-confetti as a client component and says it will not run in Node

API stability5/5Version 1.9.4 keeps the long-standing function-plus-options API, with create(), reset(), shapeFromPath(), and shapeFromText() as the small set of extensions. Its release changed an OffscreenCanvas support check rather than user-facing calls. One future-facing warning is explicit in the README: disableForReducedMotion defaults to false today but may switch in a later major, so production code should set it rather than inherit the default.
Docs5/5The README lists every launch option with defaults and then explains behavior that changes integration decisions. It says overlapping calls share a canvas and promise, reset resolves pending promises, worker mode transfers canvas ownership, CSS sizing alone can blur output, and text particles capture the loaded font at creation time. The hosted demo also returns HTTP 200 and provides a quick visual check of the controls.
Maintenance3/5GitHub reports an unarchived repository with 12,709 stars, 41 open issues and pull requests combined, and its latest push on October 25, 2025. Release 1.9.4 shipped that day with a targeted fix for OffscreenCanvas environments that expose the API without usable bitmap drawing. The pace is slow compared with framework packages, but the maintained surface is a compact canvas utility rather than a changing platform.
Ecosystem5/5The npm downloads endpoint recorded 7,498,755 downloads for August 18 through August 24, 2026. Installation adds no direct or peer dependencies, and distribution works through npm or a browser script. Because the public call is plain JavaScript and does not depend on React, Vue, or another component model, framework wrappers are optional. The tradeoff is that the package supplies no TypeScript declarations in the measured 1.9.4 tarball.

Use it if

  • A purchase, signup, achievement, or game event needs a short browser-only celebration with a programmable origin and palette
  • You need emoji or single-color SVG path particles but do not need a general particle engine
  • The effect should run on a dedicated canvas, with an optional worker path for browsers that support canvas transfer
  • The interface still communicates success when motion is disabled and you will set disableForReducedMotion explicitly
Skip it if

Setup reality

We installed canvas-confetti 1.9.4 in a clean Node 22 container in 0.8 seconds. The result was one package and 1 MB on disk. It declares zero direct dependencies and zero peer dependencies, and npm audit found zero known vulnerabilities. The package is 120 KB unpacked, CommonJS, and has no exports map. Both require() and ESM import loaded it. We found no TypeScript declarations. Our esbuild check measured 10.6 KB minified and 4.3 KB gzipped.

The successful module load does not make this a server-side library. Its README calls it a client component and says it does not run in Node, so call it from a browser event or client effect. With the default function, the package creates and reuses a page canvas. A custom canvas needs correct bitmap dimensions as well as CSS dimensions; resize: true lets the library keep those dimensions in sync. Keep the function returned by confetti.create() instead of recreating it for each burst.

Motion preferences require an explicit choice in 1.9.4. Set disableForReducedMotion: true, then make the underlying status change or message work without particles. Calls that overlap add particles to the current canvas and share its completion promise. reset() clears the animation and resolves that promise immediately, so application code must record cancellation separately if the distinction matters. Particle count and ticks both add browser work, even when calls share one animation loop.

Worker mode has a sharp ownership rule: once useWorker transfers a custom canvas, main-thread code must stop reading or drawing on it. Text shapes are rasterized when shapeFromText runs, so wait for a web font before creating them and pass the same scalar at creation and launch. SVG shapes depend on Path2D. The README also advises caching the computed path matrix and regenerating it after upgrading the package.

Patterns

Launch one accessible burst fire-basic-burst

import confetti from 'canvas-confetti';

await confetti({ particleCount: 80, spread: 65, disableForReducedMotion: true });

With reduced motion enabled at the OS level, disableForReducedMotion makes this call resolve without drawing; the success state must remain visible.

Aim a burst at a control launch-from-button

const box = button.getBoundingClientRect();
confetti({ origin: { x: (box.left + box.width / 2) / innerWidth, y: (box.top + box.height / 2) / innerHeight }, disableForReducedMotion: true });

origin uses viewport fractions from 0 to 1, so recalculate the button rectangle after scrolling or layout changes.

Fire from both sides shoot-side-cannons

const base = { particleCount: 45, spread: 55, disableForReducedMotion: true };
confetti({ ...base, angle: 60, origin: { x: 0, y: 0.65 } });
confetti({ ...base, angle: 120, origin: { x: 1, y: 0.65 } });

Two calls made before completion add particles to the same default canvas and return the same completion promise.

Choose a palette and built-in shape set-colors-and-shapes

confetti({ particleCount: 100, colors: ['#0f766e', '#f59e0b', '#ffffff'], shapes: ['star'], scalar: 0.9, disableForReducedMotion: true });

Version 1.9.4 recognizes square, circle, and star; repeating a name in shapes changes its share of the mix.

Bind an instance to one canvas use-custom-canvas

const canvas = document.querySelector('#reward-canvas');
const reward = confetti.create(canvas, { resize: true, disableForReducedMotion: true });
reward({ particleCount: 70, spread: 90 });

Call confetti.create() once for this element and retain the returned function; resize: true updates its bitmap dimensions.

Move rendering to a worker render-with-worker

const reward = confetti.create(canvas, { resize: true, useWorker: true, disableForReducedMotion: true });
reward({ particleCount: 120, spread: 110 });

A successful worker transfer gives ownership of this canvas to the worker, and later main-thread access can throw.

Build a particle from an SVG path create-svg-shape

const triangle = confetti.shapeFromPath({ path: 'M0 10 L5 0 L10 10z' });
confetti({ shapes: [triangle], disableForReducedMotion: true });

shapeFromPath needs Path2D and fills the supplied path with one color; reuse its matrix instead of computing it during every celebration.

Rasterize an emoji at launch scale create-emoji-shape

const scalar = 2;
const trophy = confetti.shapeFromText({ text: '🏆', scalar });
confetti({ shapes: [trophy], scalar, disableForReducedMotion: true });

shapeFromText captures a bitmap once; the same scalar at creation and launch avoids enlarging a lower-resolution image.

Wait for a web font wait-for-font

await document.fonts.load('700 24px Reward');
const word = confetti.shapeFromText({ text: 'WIN', fontFamily: 'Reward', color: '#7c3aed', scalar: 2 });

document.fonts.load() must finish before shapeFromText() if the captured glyph should use that font rather than a fallback.

Cap a repeating effect at two seconds run-bounded-loop

const endAt = performance.now() + 2000;
function tick(now) {
  confetti({ particleCount: 4, origin: { x: Math.random(), y: 0.7 }, disableForReducedMotion: true });
  if (now < endAt) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

The 2,000 ms deadline bounds repeated canvas work; particleCount and ticks still affect CPU and battery use.

Clear particles early cancel-animation

const completion = confetti({ particleCount: 200 });
function cancel() { confetti.reset(); }
await completion;

reset() resolves the current promise instead of rejecting it, so store a separate cancellation flag when later logic needs the reason.

Import only in the browser defer-browser-import

async function celebrateInBrowser() {
  if (typeof window === 'undefined') return;
  const { default: confetti } = await import('canvas-confetti');
  await confetti({ disableForReducedMotion: true });
}

The README says the package does not run in Node; invoke this helper from client code after window exists.

Alternatives

PackageRegistryPick it when
js-confettinpmUse it when a class-based API and emoji confetti cover the whole job
party-jsnpmUse it when you need reusable particle emitters and effects other than confetti
@tsparticles/confettinpmUse it when tsParticles is already in the application or its larger option set is needed

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.