Installation
Use the CLI for the fastest setup, or copy the file manually.
Run this command in your project root. The CLI will create components/ui/ and write the file automatically.
$ npx @nehal712521/inprogress add button
β Fetching from registryβ¦
β Created components/ui/AnimatedButton.tsx
β Done!
See all available components β npx @nehal712521/inprogress list
Usage
Import the component and pick a variant.
Variants
Four animation styles, each a pure CSS effect.
Shimmer
A light-streak sweeps across the button on a loop β great for primary CTAs.
<AnimatedButton variant="shimmer">Get Started</AnimatedButton>Glow
A soft ambient glow pulses around the border. Hover reveals an intense halo.
<AnimatedButton variant="glow">Learn More</AnimatedButton>Pulse
A ring expands outward from the button in a heartbeat rhythm β draws the eye.
<AnimatedButton variant="pulse">Subscribe</AnimatedButton>Ripple
Click anywhere on the button to spawn a ripple wave from your cursor position.
<AnimatedButton variant="ripple">Click Me</AnimatedButton>Sizes
<AnimatedButton size="sm">Small</AnimatedButton>
<AnimatedButton size="md">Medium</AnimatedButton>
<AnimatedButton size="lg">Large</AnimatedButton>Disabled State
<AnimatedButton variant="shimmer" disabled>Disabled</AnimatedButton>Component Source
Copy this into components/ui/AnimatedButton.tsx
"use client";
import React, { useRef } from "react";
type Variant = "shimmer" | "glow" | "pulse" | "ripple";
type Size = "sm" | "md" | "lg";
interface AnimatedButtonProps {
children: React.ReactNode;
variant?: Variant;
size?: Size;
disabled?: boolean;
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
className?: string;
type?: "button" | "submit" | "reset";
fullWidth?: boolean;
}
const sizeMap: Record<Size, string> = {
sm: "px-4 py-1.5 text-sm",
md: "px-6 py-2.5 text-sm",
lg: "px-8 py-3.5 text-base",
};
export default function AnimatedButton({
children,
variant = "shimmer",
size = "md",
disabled = false,
onClick,
className = "",
type = "button",
fullWidth = false,
}: AnimatedButtonProps) {
const btnRef = useRef<HTMLButtonElement>(null);
const rippleRef = useRef<HTMLSpanElement>(null);
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
if (variant === "ripple" && btnRef.current && rippleRef.current) {
const btn = btnRef.current;
const ripple = rippleRef.current;
const rect = btn.getBoundingClientRect();
const size = Math.max(rect.width, rect.height) * 2;
ripple.style.width = `${size}px`;
ripple.style.height = `${size}px`;
ripple.style.left = `${e.clientX - rect.left - size / 2}px`;
ripple.style.top = `${e.clientY - rect.top - size / 2}px`;
ripple.classList.remove("animate-ripple");
void ripple.offsetWidth;
ripple.classList.add("animate-ripple");
}
onClick?.(e);
};
return (
<>
<style>{`/* ... paste the CSS from the source file ... `}</style>
<button
ref={btnRef}
type={type}
disabled={disabled}
onClick={handleClick}
className={`animated-btn ${sizeMap[size]} btn-${variant} ${fullWidth ? "w-full" : ""} ${className}`}
>
{variant === "ripple" && <span ref={rippleRef} className="ripple-dot" />}
<span className="relative z-10 flex items-center gap-2">{children}</span>
</button>
</>
);
}API Reference
All props accepted by AnimatedButton.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "shimmer" | "glow" | "pulse" | "ripple" | "shimmer" | Controls the animation style. |
| size | "sm" | "md" | "lg" | "md" | Controls padding and font size. |
| disabled | boolean | false | Disables the button and fades it out. |
| fullWidth | boolean | false | Makes the button stretch to full container width. |
| onClick | (e: MouseEvent) => void | β | Click handler forwarded to the native button. |
| className | string | "" | Extra Tailwind / CSS classes merged in. |
| type | "button" | "submit" | "reset" | "button" | Native button type attribute. |