Party Popper Confetti for React

Confetti celebration effect on click. Wraps any trigger element and fires particles on interaction.

Component

Installation

 

Usage

Import

Add the PartyPopper import.

import { PartyPopper } from "@/components/party-popper";

Use

Wrap any clickable element.

<PartyPopper>
  <Button>Celebrate</Button>
</PartyPopper>;

Guidelines

  • Wrap any clickable element (button, icon, div) as children.
  • Particles emit from the center of the trigger element.
  • Respects prefers-reduced-motion; no animation when the user has reduced motion enabled.

Props

All props are optional unless marked required. Use these to customize every aspect of the component.

PropTypeDefaultDescription
childrenReact.ReactNode-The clickable trigger element.
classNamestring-Additional CSS classes for the trigger wrapper.
particleCountnumber12Number of circular/square particles to emit.
streamerCountnumber4Number of streamer particles to emit.
direction"center" | "up" | "down" | "left" | "right""center"Direction particles fly. "center" spreads in all directions; others aim in a focused cone.
colorsreadonly string[]-Array of hex colors for particles. Defaults to a vibrant palette.
particleSizeMinnumber8Minimum particle size in pixels.
particleSizeMaxnumber12Maximum particle size in pixels.
streamerWidthMinnumber25Minimum streamer width in pixels.
streamerWidthMaxnumber35Maximum streamer width in pixels.
streamerHeightMinnumber4Minimum streamer height in pixels.
streamerHeightMaxnumber6Maximum streamer height in pixels.

Accessibility

  • The trigger is a native button element with onClick, so it is keyboard operable out of the box and fires on Enter and Space without extra handlers.
  • It adds no aria-label or role, so the accessible name comes entirely from the wrapped children; pass labelled content so screen reader users know what the trigger does.
  • The wrapper button strips its own styling with border-0 bg-transparent p-0 and adds no focus-visible ring, so ensure the children render a visible focus indicator.
  • The particle overlay is marked aria-hidden true and pointer-events-none, so the decorative confetti is correctly hidden from assistive technology and never intercepts clicks.
  • It honours prefers-reduced-motion reduce by checking window.matchMedia in the pop handler and returning early, so no particles are created or animated for users who prefer reduced motion.

Performance

  • Only transform via GSAP x, y and rotation plus opacity are animated, which are GPU compositable properties that avoid layout and paint thrash.
  • GSAP timelines drive the motion using its internal requestAnimationFrame loop rather than per particle setInterval or manual rAF code.
  • Every created particle and streamer node is removed in the timeline onComplete callback, so DOM nodes are cleaned up after each burst and do not accumulate.
  • The prefers-reduced-motion check gates all DOM creation and animation, skipping the work entirely when reduced motion is requested.
  • No will-change is set and matchMedia is read on each render rather than cached, but the component leaves no lingering event listeners or timers between bursts.

Examples

Basic

Wrap a button to trigger confetti on click.

import { PartyPopper } from "@/components/party-popper";
import { Button } from "@/components/ui/button";

export function PartyPopperBasic() {
  return (
    <PartyPopper>
      <Button>Celebrate</Button>
    </PartyPopper>
  );
}

Direction

Use the direction prop to aim particles. Options: "center" (default), "up", "down", "left", "right".

import { PartyPopper } from "@/components/party-popper";
import { Button } from "@/components/ui/button";

export function PartyPopperDirectionUp() {
  return (
    <PartyPopper direction="up">
      <Button>🎉 Fire Up</Button>
    </PartyPopper>
  );
}

Last updated on Jun 19

Made with ❤️ by Pulkit &

© 2026 Pulkit. All rights reserved

Last updated: