Confetti — <mv-confetti-button>

Physics-based canvas confetti (gravity, drag, 3D tumble, wobble): a standalone confetti() function, cannons / fireworks / stars / emoji presets, a trigger button and a press-and-hold “cool” mode.

CategoryMicro-interactions
TypeWeb Component (<mv-confetti-button>)
Statusstable
Keywordsconfetti, celebration, canvas, particles, emoji, cool-mode, success

When to use

Avoid when

Install

node scripts/add.mjs confetti --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["confetti"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/canvas.js, core/element.js, core/motion.js, components/confetti/confetti.js.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div style="display:grid;gap:1.25rem;justify-items:center;text-align:center">
  <div style="display:grid;gap:.35rem">
    <strong style="font-size:1.05rem">Payment confirmed. Thanks, Priya!</strong>
    <span style="color:var(--mv-fg-muted);font-size:.85rem">Order #48213 · arriving Thursday</span>
  </div>
  <div style="display:flex;flex-wrap:wrap;gap:.75rem;justify-content:center">
    <mv-confetti-button>
      <button class="mv-button" data-shape="pill">🎉 Celebrate</button>
    </mv-confetti-button>
    <mv-confetti-button preset="stars">
      <button class="mv-button" data-variant="secondary" data-shape="pill">Stars</button>
    </mv-confetti-button>
    <mv-confetti-button emoji="🥯,☕,🥞" scalar="1.3" count="36" spread="100">
      <button class="mv-button" data-variant="outline" data-shape="pill">Free breakfast</button>
    </mv-confetti-button>
    <mv-confetti-button preset="cannons">
      <button class="mv-button" data-variant="outline" data-shape="pill">Cannons</button>
    </mv-confetti-button>
    <mv-confetti-button preset="fireworks">
      <button class="mv-button" data-variant="outline" data-shape="pill">Fireworks</button>
    </mv-confetti-button>
  </div>
  <div style="display:flex;flex-wrap:wrap;gap:.75rem;justify-content:center;align-items:center">
    <mv-confetti-button preset="cool" emoji="💜,✨">
      <button class="mv-button" data-variant="ghost">Hold for a shower of hearts</button>
    </mv-confetti-button>
    <button class="mv-button" data-variant="ghost" data-mv-confetti data-confetti-shapes="circle" data-confetti-colors="var(--mv-accent),var(--mv-success)">data-mv-confetti</button>
  </div>
</div>

API

Attributes

NameTypeDefaultDescription
presetburst | stars | cannons | fireworks | coolburstburst/stars fire from the clicked button; cannons/fireworks cover the screen; cool = continuous stream while the pointer is held.
countnumber80Confetti pieces per burst.
spread / angledegrees70 / 90Cone width and direction (90 = straight up).
velocity / gravity / scalarnumber42 / 0.55 / 1Initial velocity, gravity, size.
colorscomma-separated list of CSS colorsColors (tokens accepted). Default: accent + a festive palette.
shapessquare,circle,starsquare,square,circleShapes picked at random.
emojicomma-separated listReplaces shapes with emoji/text (rasterized once).
disabledbooleanStops firing.
data-mv-confettipreset (on any element)Declarative trigger without a wrapper; options via data-confetti-count, -spread, -angle, -velocity, -gravity, -scalar, -colors, -shapes, -emoji.

Methods

NameDescription
confetti(options)Export: { particleCount, angle, spread, startVelocity, decay, gravity, drift, ticks, scalar, origin: {x,y} (0..1 viewport) | element, colors, shapes, emoji, flat, respectMotion }. Returns a Promise that resolves once everything has landed.
confetti.cannons / .fireworks / .stars (options)Presets; cannons and fireworks accept duration (ms).
confetti.reset()Clears everything immediately.
coolMode(el, options)Export: streams particles under the pointer while it is held on el; returns a cleanup function.
fire(from?)<mv-confetti-button> method: fires the preset from an element.

Events

NameDescription
mv-fireOn every <mv-confetti-button> shot; detail = { preset }.

Content structure

NameDescription
(child)The trigger button or link (stays a real <button>).

Accessibility

Decorative: a single aria-hidden canvas, pointer-events: none, placed in the top layer (above modals) and removed from the DOM as soon as the last piece has landed — no rAF loop when idle. Reduced motion: no confetti (the promise resolves immediately) and the button keeps its normal feedback; force it with respectMotion: false. The child button keeps its accessible name; announce the success itself with text or a live region.