Skip to content
WANCRAFT

E.81Backgrounds & Effects

Confetti

Canvas confetti bursts with flipping squares, circles and strips, fired by ref, hook or trigger.

NewReactCanvasTailwindintermediate

Overview

Confetti is a dependency-free canvas layer for celebrations. Fire bursts imperatively with the useConfetti() controller (or a ref), from an element or a point, or declaratively by changing the trigger prop. Each piece is a square, circle or paper strip with a fake 3D flip (its scale oscillates and the back face is shaded), plus gravity, air drag, wobble and wind. The rAF loop only runs while pieces are alive and the canvas is cleared the moment the last one settles. With reduced motion there is no burst: a brief static scatter (or nothing), and an optional polite announcement for screen readers.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/confetti.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/confetti.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/confetti.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { Confetti, useConfetti } from "@/components/ui/confetti";

export function ConfettiExample() {
  const confetti = useConfetti();

  return (
    <>
      <button type="button" onClick={(e) => confetti.fire({ origin: e.currentTarget })}>
        Place order
      </button>
      <Confetti controller={confetti} announce="Order placed. Thank you!" />
    </>
  );
}

03Props

PropTypeDefaultDescription
controllerConfettiController—From useConfetti(): { fire(options?), clear() } callable from any handler.
refRef<ConfettiHandle>—Alternative imperative handle: { fire(options?), clear() }.
triggerunknown—Fires a burst whenever the value changes (not on mount).
countnumber120Pieces per burst (at most 1500 alive at once).
anglenumber90Launch direction in degrees; 90 is straight up.
spreadnumber70Cone width in degrees around angle; 360 bursts in all directions.
velocitynumber32Launch speed in px per frame at 60fps (each piece gets 50–100%).
gravitynumber1Gravity multiplier.
dragnumber0.92Fraction of speed kept per frame (0.8–0.99).
windnumber0Constant sideways push; negative blows left.
colorsstring[]CONFETTI_COLORSPiece colours (any CSS colour); the back face is shaded automatically.
shape"mixed" | "square" | "circle" | "strip""mixed"Piece shape.
sizenumber1Piece size multiplier.
originElement | { x: number; y: number }{ x: 0.5, y: 0.6 }Default origin: an element's centre, or fractions (0–1) of the canvas.
position"fixed" | "absolute""fixed"Cover the viewport, or fill the nearest positioned ancestor.
announcestring—Text announced via a polite live region on every burst.
reducedMotion"static" | "none""static"With prefers-reduced-motion: a 1.6s static scatter, or nothing.
...propsHTMLAttributes<HTMLCanvasElement>—Forwarded to the canvas (className, style, z-index…).

04Features

  • 01useConfetti() controller or a ref handle: fire(options) and clear()
  • 02Declarative trigger prop for state-driven celebrations
  • 03Origin from an element's centre or from fractional coordinates
  • 04Squares, circles and strips with a 3D-style flip and shaded back face
  • 05Gravity, drag, wobble and wind; per-burst option overrides
  • 06Loop runs only while pieces are alive; canvas cleared when settled; DPR ≤ 2
motion · tweeninput · click

05Accessibility

  • The canvas is aria-hidden and never intercepts pointer events.
  • Optional announce text is spoken through a polite role="status" live region on each burst.
  • prefers-reduced-motion: no burst. By default a small static scatter appears for 1.6s; reducedMotion="none" shows nothing.
  • Purely decorative: the action that triggers it should communicate its own result.

06Limitations

  • A fixed-position canvas sits above the page at z-50 while pieces fly; adjust with className if your overlays stack higher.