mrkeyoor.com_
Sat 08 Aug 17:43 UTC
npmWeb Frontendupdated 08 Aug 2026

canvas-confetti

Small browser-only confetti renderer that draws animated particles on a generated or supplied canvas. One function controls particle count, colors, shapes, launch angle, spread, velocity, gravity, drift, duration, origin, scale, and stacking. It returns a promise that settles when all current bursts finish, can render through a worker, and includes helpers for SVG-path and emoji shapes. It is a focused celebration effect, not a general particle engine or server-side image renderer.

Verdict

A good small dependency for an occasional, nonessential browser celebration. Enable reduced-motion support, keep bursts bounded, and avoid worker mode on any canvas the rest of your application still owns.

API stability5/5The main confetti(options) function and its particle options are compact and additive, while create, reset, shapeFromPath, and shapeFromText cover advanced cases without changing the basic call. Version 1.9.4 remains on the long-running 1.x line. A future major may change the reduced-motion default, which the README explicitly says is under consideration.
Docs5/5The README documents every option with defaults, promise reuse, custom canvases, worker ownership, resizing, reduced motion, Path2D and text-shape limitations, reset semantics, and several complete effects. The warnings are unusually direct and useful. There is no large separate manual, but the focused API is covered in enough depth to use safely.
Maintenance3/5Version 1.9.4 was released and the repository was pushed on October 25, 2025. That release fixed an OffscreenCanvas compatibility error and updated automation, showing targeted upkeep. Activity is not frequent and the repository has an existing combined backlog of issues and pull requests, but the project is not archived and its narrow API is mature.
Ecosystem5/5The package recorded 7,341,707 downloads in the measured week, has 12,690 GitHub stars, no runtime dependencies, and works with any browser framework or plain scripts. CDN and npm builds are documented, while small wrappers exist across frontend ecosystems. Its reach is broad for a novelty effect, though it intentionally offers few integration layers.

Use it if

  • You need a short celebratory browser effect with no framework dependency and a small measured payload
  • You want to launch from a button, card, or screen coordinate and tune basic particle physics without building a canvas loop
  • You will enable disableForReducedMotion and provide a non-motion success signal as the primary feedback
  • You need custom emoji or single-color path shapes and can accept their browser and rendering constraints
Skip it if

Setup reality

npm install canvas-confetti adds no runtime dependencies and version 1.9.4 measured about 4.3 KB gzipped. The hidden constraint is environment: it touches browser canvas APIs and cannot run in Node, so SSR frameworks must import or call it only on the client after window and document exist. The default function creates and reuses a full-page canvas; repeated calls before completion share one promise and add particles to the same active animation. Accessibility is opt-in because disableForReducedMotion defaults to false. Set it to true globally or on every burst, then make sure the success state is also conveyed with text, focus, sound only where appropriate, or another non-motion cue. A custom canvas does not automatically match its CSS display size; enable resize or set its pixel dimensions yourself, and persist one custom confetti instance instead of recreating it for the same element. useWorker can reduce main-thread work, but it transfers the canvas to a worker and your code must stop reading or drawing it. Higher particleCount, ticks, large Path2D shapes, and repeated bursts still consume CPU and battery. shapeFromText rasterizes at creation time, so its scalar must match the burst scalar to avoid blur and web fonts must finish loading first. shapeFromPath matrix calculation is expensive and the README recommends computing and caching the matrix ahead of time, then regenerating it after library updates. reset stops animation and resolves outstanding promises rather than rejecting them, which can make awaiting code look like a normal completion.

Patterns

Launch an accessible default burstfire-basic-burst

import confetti from 'canvas-confetti';

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

The promise resolves immediately when reduced motion is requested, so essential success handling must not depend on seeing particles.

Launch from a button positionlaunch-from-element

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

origin uses page-relative fractions from 0 to 1, not CSS pixels. Recalculate after layout changes.

Create opposing burstsfire-from-both-sides

const common = { particleCount: 45, spread: 55, disableForReducedMotion: true };
await Promise.all([
  confetti({ ...common, angle: 60, origin: { x: 0, y: 0.65 } }),
  confetti({ ...common, angle: 120, origin: { x: 1, y: 0.65 } }),
]);

Calls made during one active global animation return the same completion promise and share the generated canvas.

Use brand colors and starscustomize-palette

confetti({
  particleCount: 100,
  colors: ['#2563eb', '#7c3aed', '#f59e0b'],
  shapes: ['star'],
  scalar: 0.9,
  disableForReducedMotion: true,
});

Built-in shapes are square, circle, and star. Colors use CSS-style hexadecimal strings.

Limit particles to one canvascreate-custom-canvas

const canvas = document.querySelector('#celebration');
const celebrate = confetti.create(canvas, {
  resize: true,
  disableForReducedMotion: true,
});

celebrate({ particleCount: 80, spread: 90 });

Create and persist one instance per canvas. resize lets the library change the canvas pixel dimensions as its display size changes.

Move a dedicated canvas to a workerrender-in-worker

const celebrate = confetti.create(canvas, {
  resize: true,
  useWorker: true,
  disableForReducedMotion: true,
});

celebrate({ particleCount: 150, spread: 120 });

After worker transfer, do not read from or draw on this canvas on the main thread. Removing it is still allowed.

Create a filled SVG path shapemake-path-shape

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

confetti({
  shapes: [triangle],
  disableForReducedMotion: true,
});

Path shapes require Path2D, are filled in one color, and matrix calculation should be cached for production.

Render emoji particles sharplymake-emoji-shape

const scalar = 2;
const rocket = confetti.shapeFromText({ text: '🚀', scalar });

confetti({
  shapes: [rocket],
  scalar,
  disableForReducedMotion: true,
});

Use the same scalar when creating and firing the rasterized text shape or the emoji can look blurry.

Create a text shape after font loadingwait-for-web-font

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

shapeFromText rasterizes once. If the font is not loaded first, the fallback font is permanently captured in that shape.

Run a bounded animation looprun-timed-fireworks

const end = performance.now() + 2_000;

function frame(now) {
  confetti({
    particleCount: 4,
    spread: 70,
    origin: { x: Math.random(), y: 0.7 },
    disableForReducedMotion: true,
  });
  if (now < end) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

Keep the duration and particles per frame low; repeated bursts share one canvas but still add rendering work.

Stop and clear current particlesstop-active-confetti

const done = confetti({ particleCount: 200 });

function cancelCelebration() {
  confetti.reset();
}

await done;

reset resolves outstanding promises immediately rather than rejecting them, so completion does not prove every particle finished naturally.

Import safely in an SSR applicationload-only-in-browser

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

The package is browser-only. Call this from a client event or effect, never during server rendering.

Alternatives

PackageRegistryPick it when
js-confettinpmYou want an equally focused confetti API with emoji support and prefer its class-based interface
party-jsnpmYou need configurable emitters, templates, and particle effects beyond one confetti burst
@tsparticles/confettinpmYou already use tsParticles or need a confetti preset inside its much larger particle ecosystem