react-confetti-burst 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +111 -0
- package/README.md +532 -387
- package/dist/cjs/index.js +3 -3
- package/dist/confetti.browser.js +9 -0
- package/dist/esm/index.js +3 -3
- package/dist/types/index.d.ts +322 -2
- package/package.json +105 -83
package/README.md
CHANGED
|
@@ -1,387 +1,532 @@
|
|
|
1
|
-
# react-confetti-burst 🎉
|
|
2
|
-
|
|
3
|
-
A high-performance, zero-dependency React confetti component with realistic particle physics using the native Canvas API.
|
|
4
|
-
|
|
5
|
-
[](https://badge.fury.io/js/react-confetti-burst)
|
|
6
|
-
[](https://www.typescriptlang.org/)
|
|
7
|
-
[](https://bundlephobia.com/package/react-confetti-burst)
|
|
8
|
-
[](https://opensource.org/licenses/MIT)
|
|
9
|
-
|
|
10
|
-
🎮 **[Live Playground](https://ihakalanka.github.io/confetti-burst-playground/)** | 📦 **[GitHub](https://github.com/ihakalanka/react-confetti-burst)**
|
|
11
|
-
|
|
12
|
-
## Features
|
|
13
|
-
|
|
14
|
-
- 🚀 **Zero dependencies** - Pure React + Canvas API
|
|
15
|
-
- 🎯 **Directional bursts** - Up, down, left, right, radial, or custom angles
|
|
16
|
-
- ⚡ **High performance** - Optimized canvas rendering with 60fps
|
|
17
|
-
- 🎨 **Realistic physics** - Wobble, tilt, roll, and rotate effects
|
|
18
|
-
- 📦 **Tiny bundle** -
|
|
19
|
-
- 🔷 **TypeScript first** - Full type safety built-in
|
|
20
|
-
- ♿ **Accessible** - Respects `prefers-reduced-motion`
|
|
21
|
-
|
|
22
|
-
## Installation
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm install react-confetti-burst
|
|
26
|
-
# or
|
|
27
|
-
yarn add react-confetti-burst
|
|
28
|
-
# or
|
|
29
|
-
pnpm add react-confetti-burst
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Start
|
|
33
|
-
|
|
34
|
-
### The Simplest Way - ConfettiButton
|
|
35
|
-
|
|
36
|
-
```tsx
|
|
37
|
-
import { ConfettiButton } from 'react-confetti-burst';
|
|
38
|
-
|
|
39
|
-
function App() {
|
|
40
|
-
return (
|
|
41
|
-
<ConfettiButton>
|
|
42
|
-
Click me! 🎉
|
|
43
|
-
</ConfettiButton>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Using the Hook - useConfetti
|
|
49
|
-
|
|
50
|
-
```tsx
|
|
51
|
-
import { useConfetti } from 'react-confetti-burst';
|
|
52
|
-
|
|
53
|
-
function App() {
|
|
54
|
-
const { fire } = useConfetti();
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<button onClick={(e) => fire({ x: e.clientX, y: e.clientY })}>
|
|
58
|
-
Celebrate!
|
|
59
|
-
</button>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Functional API - confetti()
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
import { confetti } from 'react-confetti-burst';
|
|
68
|
-
|
|
69
|
-
// Basic burst from center
|
|
70
|
-
confetti();
|
|
71
|
-
|
|
72
|
-
// With options
|
|
73
|
-
confetti({
|
|
74
|
-
particleCount: 150,
|
|
75
|
-
size: 4,
|
|
76
|
-
spread: 70,
|
|
77
|
-
origin: { x: 0.5, y: 0.5 }
|
|
78
|
-
});
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## confetti() Options
|
|
82
|
-
|
|
83
|
-
| Option | Type | Default | Description |
|
|
84
|
-
|--------|------|---------|-------------|
|
|
85
|
-
| `particleCount` | `number` | `100` | Number of confetti particles to launch |
|
|
86
|
-
| `size` | `number` | `4` | Base size of particles in pixels |
|
|
87
|
-
| `angle` | `number` | `90` | Launch angle in degrees (90 = straight up) |
|
|
88
|
-
| `spread` | `number` | `45` | Spread angle in degrees |
|
|
89
|
-
| `startVelocity` | `number` | `45` | Initial velocity in pixels per frame |
|
|
90
|
-
| `decay` | `number` | `0.94` | Speed decay factor (0-1) |
|
|
91
|
-
| `gravity` | `number` | `1` | Gravity strength (1 = full, 0 = none) |
|
|
92
|
-
| `drift` | `number` | `0` | Horizontal drift (-1 to 1) |
|
|
93
|
-
| `ticks` | `number` | `200` | Animation duration in frames |
|
|
94
|
-
| `origin` | `{ x, y }` | `{ x: 0.5, y: 0.5 }` | Origin position (0-1 coordinates) |
|
|
95
|
-
| `colors` | `string[]` | Rainbow colors | Array of hex colors |
|
|
96
|
-
| `shapes` | `string[]` | `['square', 'circle']` | Particle shapes |
|
|
97
|
-
| `scalar` | `number` | `1` | Scale multiplier for particle size |
|
|
98
|
-
| `flat` | `boolean` | `false` | Disable 3D effects (2D mode) |
|
|
99
|
-
| `zIndex` | `number` | `100` | Canvas z-index |
|
|
100
|
-
| `disableForReducedMotion` | `boolean` | `false` | Respect reduced motion preference |
|
|
101
|
-
|
|
102
|
-
## API Reference
|
|
103
|
-
|
|
104
|
-
### Components
|
|
105
|
-
|
|
106
|
-
#### `<ConfettiButton>`
|
|
107
|
-
|
|
108
|
-
A button that automatically fires confetti on click.
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
import { ConfettiButton } from 'react-confetti-burst';
|
|
112
|
-
|
|
113
|
-
<ConfettiButton
|
|
114
|
-
confettiOptions={{
|
|
115
|
-
particleCount: 50,
|
|
116
|
-
spread: 60,
|
|
117
|
-
colors: ['#ff6b6b', '#4ecdc4', '#ffe66d'],
|
|
118
|
-
}}
|
|
119
|
-
>
|
|
120
|
-
Click me!
|
|
121
|
-
</ConfettiButton>
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
**Props:**
|
|
125
|
-
- `confettiOptions?: ConfettiBurstOptions` - Configuration for the confetti burst
|
|
126
|
-
- `fireOnClick?: boolean` - Whether to fire on click (default: `true`)
|
|
127
|
-
- All standard button HTML attributes
|
|
128
|
-
|
|
129
|
-
#### `<ConfettiBurst>`
|
|
130
|
-
|
|
131
|
-
Declarative component for conditional confetti.
|
|
132
|
-
|
|
133
|
-
```tsx
|
|
134
|
-
import { ConfettiBurst } from 'react-confetti-burst';
|
|
135
|
-
|
|
136
|
-
<ConfettiBurst
|
|
137
|
-
active={showConfetti}
|
|
138
|
-
origin={{ x: 500, y: 300 }}
|
|
139
|
-
options={{ particleCount: 50 }}
|
|
140
|
-
onComplete={() => setShowConfetti(false)}
|
|
141
|
-
/>
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Hooks
|
|
145
|
-
|
|
146
|
-
#### `useConfetti()`
|
|
147
|
-
|
|
148
|
-
The main hook for programmatic confetti control.
|
|
149
|
-
|
|
150
|
-
```tsx
|
|
151
|
-
import { useConfetti } from 'react-confetti-burst';
|
|
152
|
-
|
|
153
|
-
function App() {
|
|
154
|
-
const { fire, fireFromElement, isActive, stopAll } = useConfetti();
|
|
155
|
-
|
|
156
|
-
// Fire from a specific point
|
|
157
|
-
const handleClick = (e: React.MouseEvent) => {
|
|
158
|
-
fire({ x: e.clientX, y: e.clientY }, {
|
|
159
|
-
particleCount: 50,
|
|
160
|
-
direction: { direction: 'up', spread: 45 },
|
|
161
|
-
});
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
// Fire from an element's center
|
|
165
|
-
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
166
|
-
const handleButtonClick = () => {
|
|
167
|
-
fireFromElement(buttonRef.current);
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
return (
|
|
171
|
-
<>
|
|
172
|
-
<div onClick={handleClick}>Click anywhere</div>
|
|
173
|
-
<button ref={buttonRef} onClick={handleButtonClick}>
|
|
174
|
-
Fire from me!
|
|
175
|
-
</button>
|
|
176
|
-
{isActive && <p>Animation running...</p>}
|
|
177
|
-
<button onClick={stopAll}>Stop All</button>
|
|
178
|
-
</>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
**Returns:**
|
|
184
|
-
- `fire(origin, options?)` - Fire confetti from a point `{ x, y }`
|
|
185
|
-
- `fireFromElement(element, options?)` - Fire from an element's center
|
|
186
|
-
- `isActive` - Boolean indicating if any animation is running
|
|
187
|
-
- `stopAll()` - Stop all active animations
|
|
188
|
-
|
|
189
|
-
### Functional API
|
|
190
|
-
|
|
191
|
-
#### `confetti(options?)`
|
|
192
|
-
|
|
193
|
-
Fire confetti imperatively from anywhere in your code.
|
|
194
|
-
|
|
195
|
-
```tsx
|
|
196
|
-
import { confetti } from 'react-confetti-burst';
|
|
197
|
-
|
|
198
|
-
// Simple burst
|
|
199
|
-
confetti();
|
|
200
|
-
|
|
201
|
-
// Customized burst
|
|
202
|
-
confetti({
|
|
203
|
-
particleCount: 100,
|
|
204
|
-
spread: 70,
|
|
205
|
-
origin: { x: 0.5, y: 0.5 },
|
|
206
|
-
colors: ['#ff0000', '#00ff00', '#0000ff'],
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Directional burst
|
|
210
|
-
confetti({
|
|
211
|
-
particleCount: 50,
|
|
212
|
-
direction: {
|
|
213
|
-
direction: 'up',
|
|
214
|
-
spread: 45,
|
|
215
|
-
velocity: [20, 40],
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## Configuration Options
|
|
221
|
-
|
|
222
|
-
### ConfettiBurstOptions (for React components/hooks)
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
interface ConfettiBurstOptions {
|
|
226
|
-
// Number of particles (default: 100)
|
|
227
|
-
particleCount?: number;
|
|
228
|
-
|
|
229
|
-
// Base particle size in pixels (default: 4)
|
|
230
|
-
size?: number;
|
|
231
|
-
|
|
232
|
-
// Direction configuration
|
|
233
|
-
direction?: {
|
|
234
|
-
direction?: 'up' | 'down' | 'left' | 'right' | 'radial' | 'custom';
|
|
235
|
-
angle?: number; // For 'custom' direction (degrees)
|
|
236
|
-
spread?: number; // Spread angle (default: 45)
|
|
237
|
-
velocity?: [number, number]; // Min/max velocity
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// Particle appearance
|
|
241
|
-
particle?: {
|
|
242
|
-
size?: [number, number]; // Min/max size
|
|
243
|
-
colors?: string[]; // Array of colors
|
|
244
|
-
shapes?: ('square' | 'circle' | 'star' | 'triangle')[];
|
|
245
|
-
opacity?: [number, number]; // Min/max opacity
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
// Physics
|
|
249
|
-
physics?: {
|
|
250
|
-
gravity?: number; // Gravity strength (default: 0.5)
|
|
251
|
-
friction?: number; // Air friction (default: 0.99)
|
|
252
|
-
wind?: number; // Horizontal wind force
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
// Lifecycle callbacks
|
|
256
|
-
onStart?: () => void;
|
|
257
|
-
onComplete?: () => void;
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
## Particle Physics
|
|
262
|
-
|
|
263
|
-
The confetti engine features realistic particle physics with four independent effects:
|
|
264
|
-
|
|
265
|
-
- **Wobble** - Side-to-side sway like leaves falling
|
|
266
|
-
- **Tilt** - 3D rotation creating a tumbling effect
|
|
267
|
-
- **Roll** - Flip animation with darkening on the back side
|
|
268
|
-
- **Rotate** - 2D spin around the z-axis
|
|
269
|
-
|
|
270
|
-
Set `flat: true` to disable all 3D effects for a simpler 2D animation.
|
|
271
|
-
|
|
272
|
-
## Examples
|
|
273
|
-
|
|
274
|
-
### Directional Bursts
|
|
275
|
-
|
|
276
|
-
```tsx
|
|
277
|
-
import { useConfetti } from 'react-confetti-burst';
|
|
278
|
-
|
|
279
|
-
function DirectionalExample() {
|
|
280
|
-
const { fire } = useConfetti();
|
|
281
|
-
|
|
282
|
-
const fireUp = () => fire({ x: 400, y: 500 }, {
|
|
283
|
-
direction: { direction: 'up', spread: 30 },
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
const fireRadial = () => fire({ x: 400, y: 300 }, {
|
|
287
|
-
direction: { direction: 'radial' },
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
return (
|
|
291
|
-
<>
|
|
292
|
-
<button onClick={fireUp}>Fire Up ⬆️</button>
|
|
293
|
-
<button onClick={fireRadial}>Radial Burst 💥</button>
|
|
294
|
-
</>
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Custom Colors
|
|
300
|
-
|
|
301
|
-
```tsx
|
|
302
|
-
<ConfettiButton
|
|
303
|
-
confettiOptions={{
|
|
304
|
-
particle: {
|
|
305
|
-
colors: ['#FFD700', '#FF6B6B', '#4ECDC4', '#45B7D1'],
|
|
306
|
-
},
|
|
307
|
-
}}
|
|
308
|
-
>
|
|
309
|
-
Golden Burst ✨
|
|
310
|
-
</ConfettiButton>
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Form Submission Success
|
|
314
|
-
|
|
315
|
-
```tsx
|
|
316
|
-
import { confetti } from 'react-confetti-burst';
|
|
317
|
-
|
|
318
|
-
async function handleSubmit(data: FormData) {
|
|
319
|
-
const response = await submitForm(data);
|
|
320
|
-
|
|
321
|
-
if (response.success) {
|
|
322
|
-
confetti({
|
|
323
|
-
particleCount: 150,
|
|
324
|
-
size: 5,
|
|
325
|
-
spread: 70,
|
|
326
|
-
origin: { x: 0.5, y: 0.6 },
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### Firework Effect
|
|
333
|
-
|
|
334
|
-
```tsx
|
|
335
|
-
import { confetti } from 'react-confetti-burst';
|
|
336
|
-
|
|
337
|
-
// Built-in fireworks preset
|
|
338
|
-
confetti.fireworks();
|
|
339
|
-
|
|
340
|
-
// Or customize
|
|
341
|
-
confetti.fireworks({
|
|
342
|
-
particleCount: 50,
|
|
343
|
-
colors: ['#ff0000', '#ffff00', '#00ff00'],
|
|
344
|
-
});
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### School Pride (Two-sided burst)
|
|
348
|
-
|
|
349
|
-
```tsx
|
|
350
|
-
import { confetti } from 'react-confetti-burst';
|
|
351
|
-
|
|
352
|
-
confetti.schoolPride({
|
|
353
|
-
colors: ['#bb0000', '#ffffff'], // Your school colors
|
|
354
|
-
});
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Snow Effect
|
|
358
|
-
|
|
359
|
-
```tsx
|
|
360
|
-
import { confetti } from 'react-confetti-burst';
|
|
361
|
-
|
|
362
|
-
confetti.snow({
|
|
363
|
-
duration: 5000, // 5 seconds
|
|
364
|
-
colors: ['#ffffff', '#e0e0e0'],
|
|
365
|
-
});
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
##
|
|
369
|
-
|
|
370
|
-
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
1
|
+
# react-confetti-burst 🎉
|
|
2
|
+
|
|
3
|
+
A high-performance, zero-dependency React confetti component with realistic particle physics using the native Canvas API.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/react-confetti-burst)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://bundlephobia.com/package/react-confetti-burst)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
🎮 **[Live Playground](https://ihakalanka.github.io/confetti-burst-playground/)** | 📦 **[GitHub](https://github.com/ihakalanka/react-confetti-burst)**
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🚀 **Zero dependencies** - Pure React + Canvas API
|
|
15
|
+
- 🎯 **Directional bursts** - Up, down, left, right, radial, or custom angles
|
|
16
|
+
- ⚡ **High performance** - Optimized canvas rendering with 60fps
|
|
17
|
+
- 🎨 **Realistic physics** - Wobble, tilt, roll, and rotate effects
|
|
18
|
+
- 📦 **Tiny bundle** - Tree-shakable presets for optimal bundle size
|
|
19
|
+
- 🔷 **TypeScript first** - Full type safety built-in
|
|
20
|
+
- ♿ **Accessible** - Respects `prefers-reduced-motion`
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install react-confetti-burst
|
|
26
|
+
# or
|
|
27
|
+
yarn add react-confetti-burst
|
|
28
|
+
# or
|
|
29
|
+
pnpm add react-confetti-burst
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### The Simplest Way - ConfettiButton
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { ConfettiButton } from 'react-confetti-burst';
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
return (
|
|
41
|
+
<ConfettiButton>
|
|
42
|
+
Click me! 🎉
|
|
43
|
+
</ConfettiButton>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Using the Hook - useConfetti
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useConfetti } from 'react-confetti-burst';
|
|
52
|
+
|
|
53
|
+
function App() {
|
|
54
|
+
const { fire } = useConfetti();
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<button onClick={(e) => fire({ x: e.clientX, y: e.clientY })}>
|
|
58
|
+
Celebrate!
|
|
59
|
+
</button>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Functional API - confetti()
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { confetti } from 'react-confetti-burst';
|
|
68
|
+
|
|
69
|
+
// Basic burst from center
|
|
70
|
+
confetti();
|
|
71
|
+
|
|
72
|
+
// With options
|
|
73
|
+
confetti({
|
|
74
|
+
particleCount: 150,
|
|
75
|
+
size: 4,
|
|
76
|
+
spread: 70,
|
|
77
|
+
origin: { x: 0.5, y: 0.5 }
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## confetti() Options
|
|
82
|
+
|
|
83
|
+
| Option | Type | Default | Description |
|
|
84
|
+
|--------|------|---------|-------------|
|
|
85
|
+
| `particleCount` | `number` | `100` | Number of confetti particles to launch |
|
|
86
|
+
| `size` | `number` | `4` | Base size of particles in pixels |
|
|
87
|
+
| `angle` | `number` | `90` | Launch angle in degrees (90 = straight up) |
|
|
88
|
+
| `spread` | `number` | `45` | Spread angle in degrees |
|
|
89
|
+
| `startVelocity` | `number` | `45` | Initial velocity in pixels per frame |
|
|
90
|
+
| `decay` | `number` | `0.94` | Speed decay factor (0-1) |
|
|
91
|
+
| `gravity` | `number` | `1` | Gravity strength (1 = full, 0 = none) |
|
|
92
|
+
| `drift` | `number` | `0` | Horizontal drift (-1 to 1) |
|
|
93
|
+
| `ticks` | `number` | `200` | Animation duration in frames |
|
|
94
|
+
| `origin` | `{ x, y }` | `{ x: 0.5, y: 0.5 }` | Origin position (0-1 coordinates) |
|
|
95
|
+
| `colors` | `string[]` | Rainbow colors | Array of hex colors |
|
|
96
|
+
| `shapes` | `string[]` | `['square', 'circle']` | Particle shapes |
|
|
97
|
+
| `scalar` | `number` | `1` | Scale multiplier for particle size |
|
|
98
|
+
| `flat` | `boolean` | `false` | Disable 3D effects (2D mode) |
|
|
99
|
+
| `zIndex` | `number` | `100` | Canvas z-index |
|
|
100
|
+
| `disableForReducedMotion` | `boolean` | `false` | Respect reduced motion preference |
|
|
101
|
+
|
|
102
|
+
## API Reference
|
|
103
|
+
|
|
104
|
+
### Components
|
|
105
|
+
|
|
106
|
+
#### `<ConfettiButton>`
|
|
107
|
+
|
|
108
|
+
A button that automatically fires confetti on click.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { ConfettiButton } from 'react-confetti-burst';
|
|
112
|
+
|
|
113
|
+
<ConfettiButton
|
|
114
|
+
confettiOptions={{
|
|
115
|
+
particleCount: 50,
|
|
116
|
+
spread: 60,
|
|
117
|
+
colors: ['#ff6b6b', '#4ecdc4', '#ffe66d'],
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
Click me!
|
|
121
|
+
</ConfettiButton>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Props:**
|
|
125
|
+
- `confettiOptions?: ConfettiBurstOptions` - Configuration for the confetti burst
|
|
126
|
+
- `fireOnClick?: boolean` - Whether to fire on click (default: `true`)
|
|
127
|
+
- All standard button HTML attributes
|
|
128
|
+
|
|
129
|
+
#### `<ConfettiBurst>`
|
|
130
|
+
|
|
131
|
+
Declarative component for conditional confetti.
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { ConfettiBurst } from 'react-confetti-burst';
|
|
135
|
+
|
|
136
|
+
<ConfettiBurst
|
|
137
|
+
active={showConfetti}
|
|
138
|
+
origin={{ x: 500, y: 300 }}
|
|
139
|
+
options={{ particleCount: 50 }}
|
|
140
|
+
onComplete={() => setShowConfetti(false)}
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Hooks
|
|
145
|
+
|
|
146
|
+
#### `useConfetti()`
|
|
147
|
+
|
|
148
|
+
The main hook for programmatic confetti control.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { useConfetti } from 'react-confetti-burst';
|
|
152
|
+
|
|
153
|
+
function App() {
|
|
154
|
+
const { fire, fireFromElement, isActive, stopAll } = useConfetti();
|
|
155
|
+
|
|
156
|
+
// Fire from a specific point
|
|
157
|
+
const handleClick = (e: React.MouseEvent) => {
|
|
158
|
+
fire({ x: e.clientX, y: e.clientY }, {
|
|
159
|
+
particleCount: 50,
|
|
160
|
+
direction: { direction: 'up', spread: 45 },
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Fire from an element's center
|
|
165
|
+
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
166
|
+
const handleButtonClick = () => {
|
|
167
|
+
fireFromElement(buttonRef.current);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<>
|
|
172
|
+
<div onClick={handleClick}>Click anywhere</div>
|
|
173
|
+
<button ref={buttonRef} onClick={handleButtonClick}>
|
|
174
|
+
Fire from me!
|
|
175
|
+
</button>
|
|
176
|
+
{isActive && <p>Animation running...</p>}
|
|
177
|
+
<button onClick={stopAll}>Stop All</button>
|
|
178
|
+
</>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Returns:**
|
|
184
|
+
- `fire(origin, options?)` - Fire confetti from a point `{ x, y }`
|
|
185
|
+
- `fireFromElement(element, options?)` - Fire from an element's center
|
|
186
|
+
- `isActive` - Boolean indicating if any animation is running
|
|
187
|
+
- `stopAll()` - Stop all active animations
|
|
188
|
+
|
|
189
|
+
### Functional API
|
|
190
|
+
|
|
191
|
+
#### `confetti(options?)`
|
|
192
|
+
|
|
193
|
+
Fire confetti imperatively from anywhere in your code.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
import { confetti } from 'react-confetti-burst';
|
|
197
|
+
|
|
198
|
+
// Simple burst
|
|
199
|
+
confetti();
|
|
200
|
+
|
|
201
|
+
// Customized burst
|
|
202
|
+
confetti({
|
|
203
|
+
particleCount: 100,
|
|
204
|
+
spread: 70,
|
|
205
|
+
origin: { x: 0.5, y: 0.5 },
|
|
206
|
+
colors: ['#ff0000', '#00ff00', '#0000ff'],
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Directional burst
|
|
210
|
+
confetti({
|
|
211
|
+
particleCount: 50,
|
|
212
|
+
direction: {
|
|
213
|
+
direction: 'up',
|
|
214
|
+
spread: 45,
|
|
215
|
+
velocity: [20, 40],
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Configuration Options
|
|
221
|
+
|
|
222
|
+
### ConfettiBurstOptions (for React components/hooks)
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
interface ConfettiBurstOptions {
|
|
226
|
+
// Number of particles (default: 100)
|
|
227
|
+
particleCount?: number;
|
|
228
|
+
|
|
229
|
+
// Base particle size in pixels (default: 4)
|
|
230
|
+
size?: number;
|
|
231
|
+
|
|
232
|
+
// Direction configuration
|
|
233
|
+
direction?: {
|
|
234
|
+
direction?: 'up' | 'down' | 'left' | 'right' | 'radial' | 'custom';
|
|
235
|
+
angle?: number; // For 'custom' direction (degrees)
|
|
236
|
+
spread?: number; // Spread angle (default: 45)
|
|
237
|
+
velocity?: [number, number]; // Min/max velocity
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Particle appearance
|
|
241
|
+
particle?: {
|
|
242
|
+
size?: [number, number]; // Min/max size
|
|
243
|
+
colors?: string[]; // Array of colors
|
|
244
|
+
shapes?: ('square' | 'circle' | 'star' | 'triangle')[];
|
|
245
|
+
opacity?: [number, number]; // Min/max opacity
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// Physics
|
|
249
|
+
physics?: {
|
|
250
|
+
gravity?: number; // Gravity strength (default: 0.5)
|
|
251
|
+
friction?: number; // Air friction (default: 0.99)
|
|
252
|
+
wind?: number; // Horizontal wind force
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Lifecycle callbacks
|
|
256
|
+
onStart?: () => void;
|
|
257
|
+
onComplete?: () => void;
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Particle Physics
|
|
262
|
+
|
|
263
|
+
The confetti engine features realistic particle physics with four independent effects:
|
|
264
|
+
|
|
265
|
+
- **Wobble** - Side-to-side sway like leaves falling
|
|
266
|
+
- **Tilt** - 3D rotation creating a tumbling effect
|
|
267
|
+
- **Roll** - Flip animation with darkening on the back side
|
|
268
|
+
- **Rotate** - 2D spin around the z-axis
|
|
269
|
+
|
|
270
|
+
Set `flat: true` to disable all 3D effects for a simpler 2D animation.
|
|
271
|
+
|
|
272
|
+
## Examples
|
|
273
|
+
|
|
274
|
+
### Directional Bursts
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { useConfetti } from 'react-confetti-burst';
|
|
278
|
+
|
|
279
|
+
function DirectionalExample() {
|
|
280
|
+
const { fire } = useConfetti();
|
|
281
|
+
|
|
282
|
+
const fireUp = () => fire({ x: 400, y: 500 }, {
|
|
283
|
+
direction: { direction: 'up', spread: 30 },
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const fireRadial = () => fire({ x: 400, y: 300 }, {
|
|
287
|
+
direction: { direction: 'radial' },
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<>
|
|
292
|
+
<button onClick={fireUp}>Fire Up ⬆️</button>
|
|
293
|
+
<button onClick={fireRadial}>Radial Burst 💥</button>
|
|
294
|
+
</>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Custom Colors
|
|
300
|
+
|
|
301
|
+
```tsx
|
|
302
|
+
<ConfettiButton
|
|
303
|
+
confettiOptions={{
|
|
304
|
+
particle: {
|
|
305
|
+
colors: ['#FFD700', '#FF6B6B', '#4ECDC4', '#45B7D1'],
|
|
306
|
+
},
|
|
307
|
+
}}
|
|
308
|
+
>
|
|
309
|
+
Golden Burst ✨
|
|
310
|
+
</ConfettiButton>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Form Submission Success
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { confetti } from 'react-confetti-burst';
|
|
317
|
+
|
|
318
|
+
async function handleSubmit(data: FormData) {
|
|
319
|
+
const response = await submitForm(data);
|
|
320
|
+
|
|
321
|
+
if (response.success) {
|
|
322
|
+
confetti({
|
|
323
|
+
particleCount: 150,
|
|
324
|
+
size: 5,
|
|
325
|
+
spread: 70,
|
|
326
|
+
origin: { x: 0.5, y: 0.6 },
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Firework Effect
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
import { confetti } from 'react-confetti-burst';
|
|
336
|
+
|
|
337
|
+
// Built-in fireworks preset
|
|
338
|
+
confetti.fireworks();
|
|
339
|
+
|
|
340
|
+
// Or customize
|
|
341
|
+
confetti.fireworks({
|
|
342
|
+
particleCount: 50,
|
|
343
|
+
colors: ['#ff0000', '#ffff00', '#00ff00'],
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### School Pride (Two-sided burst)
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
import { confetti } from 'react-confetti-burst';
|
|
351
|
+
|
|
352
|
+
confetti.schoolPride({
|
|
353
|
+
colors: ['#bb0000', '#ffffff'], // Your school colors
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Snow Effect
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
import { confetti } from 'react-confetti-burst';
|
|
361
|
+
|
|
362
|
+
confetti.snow({
|
|
363
|
+
duration: 5000, // 5 seconds
|
|
364
|
+
colors: ['#ffffff', '#e0e0e0'],
|
|
365
|
+
});
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Presets
|
|
369
|
+
|
|
370
|
+
16 built-in presets for quick setup:
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
import { getPreset, getPresetNames, confetti } from 'react-confetti-burst';
|
|
374
|
+
|
|
375
|
+
// List all available presets
|
|
376
|
+
console.log(getPresetNames());
|
|
377
|
+
// ['default', 'celebration', 'firework', 'snow', 'rain', 'sparkle',
|
|
378
|
+
// 'confetti', 'emoji', 'hearts', 'stars', 'money', 'pride',
|
|
379
|
+
// 'christmas', 'halloween', 'newYear', 'birthday']
|
|
380
|
+
|
|
381
|
+
// Use a preset with the React hook
|
|
382
|
+
const { fire } = useConfetti();
|
|
383
|
+
const preset = getPreset('celebration');
|
|
384
|
+
fire({ x: 500, y: 300 }, preset.options);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
| Preset | Description |
|
|
388
|
+
|--------|-------------|
|
|
389
|
+
| `default` | Balanced burst with realistic paper physics |
|
|
390
|
+
| `celebration` | Big party with lots of colorful confetti |
|
|
391
|
+
| `firework` | Firework explosion with secondary bursts |
|
|
392
|
+
| `snow` | Gentle falling snowflakes |
|
|
393
|
+
| `rain` | Rainfall effect |
|
|
394
|
+
| `sparkle` | Sparkling gold stars with glow |
|
|
395
|
+
| `confetti` | Classic continuous falling confetti |
|
|
396
|
+
| `emoji` | Emoji celebration (🎉🎊🥳✨🎈) |
|
|
397
|
+
| `hearts` | Floating hearts |
|
|
398
|
+
| `stars` | Shooting stars |
|
|
399
|
+
| `money` | Money rain (💰💵💸🤑💎) |
|
|
400
|
+
| `pride` | Rainbow pride celebration |
|
|
401
|
+
| `christmas` | Christmas themed (🎄🎅🎁❄️⭐) |
|
|
402
|
+
| `halloween` | Spooky Halloween (🎃👻🦇🕷️💀) |
|
|
403
|
+
| `newYear` | New Year fireworks |
|
|
404
|
+
| `birthday` | Birthday party (🎂🎁🎈🎉🥳) |
|
|
405
|
+
|
|
406
|
+
## Custom Shapes
|
|
407
|
+
|
|
408
|
+
Create confetti with custom SVG paths, text, or emoji:
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
import { shapeFromPath, shapeFromText, shapesFromEmoji } from 'react-confetti-burst';
|
|
412
|
+
|
|
413
|
+
// SVG path shape
|
|
414
|
+
const star = shapeFromPath({
|
|
415
|
+
path: 'M0,-1 L0.588,0.809 L-0.951,-0.309 L0.951,-0.309 L-0.588,0.809 Z',
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Text/emoji shape
|
|
419
|
+
const heart = shapeFromText({ text: '❤️', scalar: 2 });
|
|
420
|
+
|
|
421
|
+
// Multiple emoji shapes
|
|
422
|
+
const partyEmoji = shapesFromEmoji(['🎉', '🎊', '✨', '🥳']);
|
|
423
|
+
|
|
424
|
+
// Use with confetti
|
|
425
|
+
fire({ x: 500, y: 300 }, {
|
|
426
|
+
particle: { shapes: [star, heart, ...partyEmoji] },
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Advanced Physics Configuration
|
|
431
|
+
|
|
432
|
+
Fine-tune particle behavior:
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
fire({ x: 500, y: 300 }, {
|
|
436
|
+
physics: {
|
|
437
|
+
gravity: 0.5, // Lower = floatier
|
|
438
|
+
drag: 0.05, // Air resistance
|
|
439
|
+
wind: 0.3, // Horizontal wind
|
|
440
|
+
windVariation: 0.1, // Wind randomness
|
|
441
|
+
wobble: true, // 3D wobble effect
|
|
442
|
+
wobbleSpeed: 2, // Wobble oscillation speed
|
|
443
|
+
flutter: true, // Paper-like flutter
|
|
444
|
+
flutterIntensity: 0.4, // Flutter strength
|
|
445
|
+
bounce: 0.5, // Floor bounce factor
|
|
446
|
+
floor: 600, // Y position of floor
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Performance Tips
|
|
452
|
+
|
|
453
|
+
- Keep `particleCount` under 200 for mobile devices
|
|
454
|
+
- Use `setMaxPoolSize()` to control memory usage
|
|
455
|
+
- Shapes like `'circle'` and `'square'` render faster than `'star'` or `'heart'`
|
|
456
|
+
- Set `flat: true` to disable 3D effects for better performance
|
|
457
|
+
- The library automatically caps device pixel ratio at 2x
|
|
458
|
+
- Particles are automatically culled when they leave the viewport
|
|
459
|
+
|
|
460
|
+
## Browser Standalone (CDN)
|
|
461
|
+
|
|
462
|
+
Use without React via the IIFE browser build:
|
|
463
|
+
|
|
464
|
+
```html
|
|
465
|
+
<script src="https://unpkg.com/react-confetti-burst/dist/confetti.browser.js"></script>
|
|
466
|
+
<script>
|
|
467
|
+
// Global `confetti` function is available
|
|
468
|
+
confetti({ particleCount: 100, spread: 70 });
|
|
469
|
+
</script>
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Or import via package exports:
|
|
473
|
+
|
|
474
|
+
```js
|
|
475
|
+
import confetti from 'react-confetti-burst/browser';
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Migration from canvas-confetti
|
|
479
|
+
|
|
480
|
+
The `confetti()` function is API-compatible with canvas-confetti:
|
|
481
|
+
|
|
482
|
+
```tsx
|
|
483
|
+
// canvas-confetti
|
|
484
|
+
import confetti from 'canvas-confetti';
|
|
485
|
+
confetti({ particleCount: 100, spread: 70 });
|
|
486
|
+
|
|
487
|
+
// react-confetti-burst (same API!)
|
|
488
|
+
import { confetti } from 'react-confetti-burst';
|
|
489
|
+
confetti({ particleCount: 100, spread: 70 });
|
|
490
|
+
|
|
491
|
+
// Additional methods
|
|
492
|
+
confetti.fireworks();
|
|
493
|
+
confetti.schoolPride({ colors: ['#bb0000', '#ffffff'] });
|
|
494
|
+
confetti.snow({ duration: 5000 });
|
|
495
|
+
confetti.burst({ x: 0.5, y: 0.3 });
|
|
496
|
+
confetti.reset();
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
## FAQ
|
|
500
|
+
|
|
501
|
+
**Q: Does it work with SSR/Next.js?**
|
|
502
|
+
A: Yes. All DOM access is guarded by `isBrowser()` checks. The library is safe to import in server environments.
|
|
503
|
+
|
|
504
|
+
**Q: Why doesn't confetti appear?**
|
|
505
|
+
A: Check if `prefers-reduced-motion` is enabled in your OS settings. The library respects this accessibility preference and will silently skip animations.
|
|
506
|
+
|
|
507
|
+
**Q: How do I control memory usage?**
|
|
508
|
+
A: Use `setMaxPoolSize(n)` to limit the particle object pool. The default is 500. Call `forceCleanup()` to immediately release all resources.
|
|
509
|
+
|
|
510
|
+
**Q: Can I use it without React?**
|
|
511
|
+
A: Yes! Use the browser standalone build (`dist/confetti.browser.js`) or the `confetti()` functional API which doesn't require React components.
|
|
512
|
+
|
|
513
|
+
## Browser Support
|
|
514
|
+
|
|
515
|
+
- Chrome 60+
|
|
516
|
+
- Firefox 55+
|
|
517
|
+
- Safari 11+
|
|
518
|
+
- Edge 79+
|
|
519
|
+
|
|
520
|
+
## Support
|
|
521
|
+
|
|
522
|
+
If you find this package helpful, consider buying me a coffee! ☕
|
|
523
|
+
|
|
524
|
+
<p><a href="https://www.buymeacoffee.com/akalankaih4"> <img align="left" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" height="50" width="210" alt="akalankaih4" /></a></p><br><br>
|
|
525
|
+
|
|
526
|
+
## License
|
|
527
|
+
|
|
528
|
+
MIT © [ihakalanka](https://github.com/ihakalanka)
|
|
529
|
+
|
|
530
|
+
## Contributing
|
|
531
|
+
|
|
532
|
+
Contributions are welcome! Please read our [contributing guidelines](https://github.com/ihakalanka/react-confetti-burst/blob/main/CONTRIBUTING.md) before submitting a PR.
|