1 GitHub star = 1 new component.

Star the repo
Feedbackfeedbackanimation

Confetti Success

Feedback with falling confetti celebration.

Live Preview

Order placed!

Usage

Copy and paste this code into your React component:

tsx
import { ConfettiFeedback } from 'react-component-kit-ui/feedback';

<ConfettiFeedback label="Order placed!" active={done} />

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/ConfettiFeedback.tsx + ConfettiFeedback.css:

ConfettiFeedback.tsx
'use client';

import type { CSSProperties, HTMLAttributes } from 'react';
import './ConfettiFeedback.css';

/**
 * ConfettiFeedback โ€” A celebration component that triggers a falling confetti animation.
 *
 * @param label - Optional. Default 'Success!'.
 * @param color - Optional. Confetti color. Default 'var(--c-primary, #6366f1)'.
 * @param active - Optional. Whether confetti is falling. Default true.
 * @param pieces - Optional. Number of confetti pieces. Default 12.
 */
export interface ConfettiFeedbackProps extends HTMLAttributes<HTMLDivElement> {
  label?: string;
  color?: string;
  active?: boolean;
  pieces?: number;
}

// Deterministic pseudo-random (0โ€“1) so server and client renders match.
const rand = (seed: number) => {
  const x = Math.sin(seed * 9301 + 49297) * 233280;
  return x - Math.floor(x);
};

export function ConfettiFeedback({
  label = 'Success!',
  color = 'var(--c-primary, #6366f1)',
  active = true,
  pieces = 12,
  className,
  ...rest
}: ConfettiFeedbackProps) {
  return (
    <div {...rest} className={['confetti-trigger', active && 'confetti-trigger--active', className].filter(Boolean).join(' ')}>
      <span className="confetti-label">{label}</span>
      <div className="confetti-container" aria-hidden="true" style={{ '--confetti-color': color } as CSSProperties}>
        {Array.from({ length: pieces }, (_, i) => (
          <div
            key={i}
            className="confetti-piece"
            style={
              {
                '--l': `${rand(i + 1) * 100}%`,
                '--d': `${rand(i + 101) * 2}s`,
                '--r': `${rand(i + 201) * 360}deg`,
                '--s': 0.5 + rand(i + 301),
              } as CSSProperties
            }
          />
        ))}
      </div>
    </div>
  );
}

export default ConfettiFeedback;
ConfettiFeedback.css
/* ConfettiFeedback โ€” ported from astro-component-kit (feedback/ConfettiFeedback.astro) */

.confetti-trigger { 
  position: relative; 
  display: flex; 
  flex-direction: column; 
  align-items: center; 
  padding: var(--sp-4, 1rem);
  width: fit-content;
  overflow: hidden;
}

.confetti-label { 
  font-size: 1.25rem; 
  font-weight: 800; 
  color: var(--c-text-1, #fff); 
  z-index: 1; 
  text-shadow: 0 4px 10px rgba(0,0,0,0.3);
}

.confetti-container { 
  position: absolute; 
  inset: 0; 
  pointer-events: none; 
  opacity: 0; 
  transition: opacity 0.3s;
}

.confetti-trigger--active .confetti-container { opacity: 1; }

.confetti-piece { 
  position: absolute; 
  left: var(--l); 
  top: -20px; 
  width: 10px; height: 10px; 
  background: var(--confetti-color); 
  border-radius: 2px; 
  transform: rotate(var(--r)) scale(var(--s));
  opacity: 0; 
}

.confetti-trigger--active .confetti-piece {
  animation: confetti-feedback-confetti-fall 2.5s linear infinite var(--d); 
}

@keyframes confetti-feedback-confetti-fall {
  0% { transform: translateY(0) rotate(0deg) scale(var(--s)); opacity: 1; }
  25% { transform: translateY(40px) rotate(90deg) translateX(10px); }
  50% { transform: translateY(80px) rotate(180deg) translateX(-10px); }
  75% { transform: translateY(120px) rotate(270deg) translateX(5px); }
  100% { transform: translateY(160px) rotate(360deg); opacity: 0; }
}

Quick Info

Category
Feedback
Filename
ConfettiFeedback.tsx
Dependencies
None โ€” pure React + CSS
Tags
feedbackanimation