shadcn.io is not affiliated with official shadcn/ui
Each press throws a burst of small pieces out from the point it landed, a little upward, and they turn, fall and fade in about a second. A keyboard press throws them from the center.
Use it for real moments of success: an order placed, a course finished, a goal reached. On an everyday action it soon gets in the way; for feedback on every press, use the Ripple Button. It wraps the Button, so variant and size work as usual. The pieces are always in the button, hidden, each with its own direction, distance, spin and color worked out from its place in the list. Their flight is CSS keyframes, which the install adds to your stylesheet; a press only writes where it landed into two CSS variables and restarts the animation, so nothing re-renders. The pieces fly over the page without moving the layout. When the system asks for reduced motion they don't fly: they fade in and out close around the button.
Installation
Usage
import { ConfettiButton } from "@/components/ui/confetti-button";<ConfettiButton>Complete order</ConfettiButton>Demos
Amount
particleCount is how many pieces one press throws, 16 by default. Eight is a small nod for an everyday task; 40, with a longer duration, is a big moment. duration is how long a piece flies in milliseconds, 1000 by default, and each piece varies a little around it.
Colors
colors takes any CSS colors, dealt out to the pieces in turn. These are shades of the destructive color mixed with color-mix(), so they still follow the theme. By default the pieces use shades of the primary, foreground and destructive colors.
Accessibility
The confetti is decoration and hidden from assistive tech: the button is announced and activated as any Button, and nothing is said about the burst. If the press finishes something, say so in text as well, such as Order placed, so everyone gets the news.
- Enter
- Activate the button and throw confetti from its center.
- Space
- Activate the button and throw confetti from its center.
FAQ
When should I use a confetti button?
For genuine success: an order confirmed, an achievement, a milestone. Used on every action it stops meaning anything, and it slows people down.
How do I throw more or fewer pieces?
Set particleCount; 16 is the default. The Amount demo shows 8 and 40. Each piece is a small element in the button, so keep it under a hundred or so.
Can I use my brand colors?
Yes. Pass colors, an array of any CSS colors, such as var(--primary) or a color-mix() of it. The pieces take them in turn. The default is shades of the theme's primary, foreground and destructive colors, so it changes with the theme.
Where does the confetti come from?
From where the press landed, measured against the button. A keyboard press has no point, so it comes from the center.
Is the burst random?
No, though it looks it. Each piece's angle steps around the circle by the golden angle, and its distance, size, spin and pace vary with its place in the list, so the burst is the same on every press and on the server, with nothing to mismatch when the page hydrates.
Will the pieces be cut off or push the layout?
They're drawn in a layer inside the button that lets them overflow, with no effect on layout and no pointer events, so they fly over neighbors. A parent with overflow: hidden still cuts them at its edge.
API Reference
ConfettiButton
data-slot="confetti-button-burst"
children?ReactNode
The label, under the burst.
colors?string[]
The pieces' colors, any CSS colors, dealt out in turn. By default shades of the theme's primary, foreground and destructive colors, so the burst follows the theme.
- Default
COLORS
duration?number
How long a piece flies before it has faded out, in milliseconds. Each piece varies a little around it.
- Default
1000
focusableWhenDisabled?boolean
Whether the button should be focusable when disabled.
- Default
false
nativeButton?boolean
Whether the component renders a native <button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).
- Default
true
particleCount?number
How many pieces one press throws.
- Default
16
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
--confetti-button-colorstring--confetti-button-durationstring
One piece's flight, give or take a fifth (1000ms).
--confetti-button-origin-xstring
Where the last press landed, from the left (50%).
--confetti-button-origin-ystring
Where the last press landed, from the top (50%).
--confetti-button-sizestringRelated
- Pro
Success Button
Progress & resultsA calmer checkmark for success
- Pro
Shake Button
Motion & feedbackFeedback for when it fails
Ripple Button
Motion & feedbackSmaller press feedback
- Pro
Counter Button
ControlsAnimated count on each press
- Pro
Download Button
Progress & resultsProgress, then a done state
Loading Button
Progress & resultsThe wait before the moment