@candiesocean/rnconfetti
v0.2.0
Published
Confetti for React Native & Expo — physics-simulated polar spawn and gravity trajectories, animated with react-native-ease. Gold, purple and indigo presets.
Maintainers
Readme
@candiesocean/rnconfetti
Confetti for React Native & Expo. Physics-simulated — each piece gets a polar
spawn angle, a velocity, and a gravity + air-resistance trajectory solved ahead of
time, then animated through rise → fall → fade with
react-native-ease.
Sprites are real multicolor glyphs (party popper, wrapped candy, lollipop, star,
heart, gem, jelly bean, rect, dot) rendered from a native font via
react-native-nano-icons —
not <View> rectangles.
Three color presets — gold (default), purple, indigo — plus a raw colors
array if you want your own ramp. Presets are colors only; the physics never changes.
Install
npm install @candiesocean/rnconfetti react-native-ease react-native-nano-iconsSetup
The sprite font is generated at prebuild from the SVGs shipped inside this package,
then linked into your native app. Add the react-native-nano-icons config plugin to
app.json, pointing at this package's sprites/ folder:
{
"expo": {
"plugins": [
[
"react-native-nano-icons",
{
"iconSets": [
{
"inputDir": "./node_modules/@candiesocean/rnconfetti/sprites",
"fontFamily": "confetti-gold"
}
]
}
]
]
}
}fontFamily must be confetti-gold — it's the family the bundled glyphmap
resolves against. Then:
npx expo prebuild
npx expo run:ios # or run:androidA native rebuild is required because the font is linked natively. This will not run
in Expo Go. If you already have other nano-icons sets, add this one alongside them in
the same iconSets array.
Codepoints are assigned deterministically from the sorted SVG set starting at
0xE900, so the TTF the plugin generates matches the glyphmap shipped here.
Setup is one-time and preset-independent. The font carries shapes, not colors — layer
colors are supplied at runtime — so fontFamily stays confetti-gold whichever
preset you use, and switching presets needs no prebuild and no native rebuild.
Usage
Two pieces: a hook that owns the particle state, and an overlay that draws it.
Cannons — dual bottom corners firing inward
import { useEffect } from 'react';
import { useWindowDimensions, View } from 'react-native';
import { ConfettiOverlay, useConfetti } from '@candiesocean/rnconfetti';
export default function BookingConfirmed() {
const { width, height } = useWindowDimensions();
const { pieces, cannon, removePiece } = useConfetti();
useEffect(() => {
cannon({ stageWidth: width, stageHeight: height });
}, [cannon, width, height]);
return (
<View style={{ flex: 1 }}>
{/* your screen */}
<ConfettiOverlay pieces={pieces} onPieceDone={removePiece} />
</View>
);
}Burst — radiating from one point
const { pieces, burst, removePiece } = useConfetti();
burst({ originX: width / 2, originY: height / 3 });ConfettiOverlay is position: absolute, fills its parent, and is
pointerEvents="box-none", so it never blocks taps. Render it last inside a
positioned parent.
Presets
<ConfettiOverlay pieces={pieces} onPieceDone={removePiece} preset="indigo" />gold (default), purple, indigo — the names are in CONFETTI_PRESETS, the ramps
in CONFETTI_PRESET_COLORS. For a custom ramp, pass colors instead; it overrides
preset:
<ConfettiOverlay pieces={pieces} onPieceDone={removePiece} colors={myRamp} />A ramp is up to six colors ordered deepest → highlight, sized to the widest
sprite (party-popper, 6 layers). Sprites with fewer layers use the leading entries,
so order is load-bearing — a light color in slot 1 makes shadows read as highlights.
API
useConfetti()
| Returns | Type | Notes |
| ------------- | ----------------------------------- | -------------------------------------------- |
| pieces | ConfettiPieceSpec[] | Live particles. Pass to ConfettiOverlay. |
| cannon | (opts: ConfettiCannonAt) => void | Dual bottom-corner cannons. |
| burst | (opts: ConfettiBurstAt) => void | Single point burst. |
| removePiece | (id: string) => void | Pass as onPieceDone; retires a dead piece. |
| clear | () => void | Drop every live particle immediately. |
type ConfettiCannonAt = { stageWidth: number; stageHeight: number; count?: number };
type ConfettiBurstAt = { originX: number; originY: number; count?: number };count defaults to 72 (DEFAULT_PARTICLE_COUNT). Concurrent particles are capped
at 240 — spawning past that drops the oldest, so repeated firing can't grow unbounded.
<ConfettiOverlay />
| Prop | Type | Notes |
| -------------- | --------------------------- | ---------------------------------------- |
| pieces | ConfettiPieceSpec[] | |
| onPieceDone | (id: string) => void | |
| preset | ConfettiPreset | 'gold' (default) · 'purple' · 'indigo' |
| colors | readonly string[] | Raw ramp, deepest → highlight. Wins over preset. |
Also exported
ConfettiParticle, ConfettiIcon, CONFETTI_FONT_FAMILY, CONFETTI_PRESETS,
CONFETTI_PRESET_COLORS, CONFETTI_GOLD_COLORS, CONFETTI_PURPLE_COLORS,
CONFETTI_INDIGO_COLORS, CONFETTI_SPRITES, CONFETTI_SPRITE_SIZES,
createBurstSpecs, createCannonSpecs, DEFAULT_PARTICLE_COUNT — plus the
ConfettiPreset type, for driving the simulation yourself.
Peer dependencies
react · react-native · expo · react-native-ease · react-native-nano-icons
License
MIT © candiesocean
