Wave Effect
Wave effect is a modern animation component designed to enrich user interaction by creating a dynamic ripple effect when clicking on buttons or any HTML element. This component generates a visual wave effect, making the user experience more interactive and visually appealing. Perfect for modern web designs. Built with Tailwind CSS and Framer Motion.
Button
Image
Colored
Blue
Green
Purple
Red
Install the following dependencies:
npm i framer-motion clsx tailwind-merge
Add util file
import { ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Copy and paste the following code into your project.
"use client";
import { useEffect, useState } from "react";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
interface WaveEffectProps {
children: React.ReactNode;
color?: string;
className?: string;
duration?: number;
}
export function WaveEffect({
children,
color,
className,
duration = 0.6,
}: WaveEffectProps) {
const [keyValue, setKeyValue] = useState<number>(0);
const [ripple, setRipple] = useState<{ x: number; y: number }>({
x: 0,
y: 0,
});
const [showRipple, setShowRipple] = useState<boolean>(false);
const [mouseUp, setMouseUp] = useState<boolean>(false);
const [animationComplete, setAnimationComplete] = useState<boolean>(false);
useEffect(() => {
if (!mouseUp && animationComplete) {
setShowRipple(false);
setAnimationComplete(false);
}
}, [mouseUp, animationComplete]);
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.width / 2;
setKeyValue((prev) => prev + 1);
setRipple({ x, y });
setMouseUp(true);
setShowRipple(true);
};
const handleAnimationComplete = () => {
setAnimationComplete(true);
};
const handleMouseUp = () => {
setMouseUp(false);
};
return (
<div
className={cn("inline-flex relative overflow-hidden", className)}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
>
{children}
{showRipple && (
<motion.span
key={keyValue}
className={cn(
"absolute aspect-square bg-black bg-opacity-30 rounded-full pointer-events-none start-0 top-0",
color
)}
initial={{ opacity: 1, scale: 0.5 }}
animate={{ opacity: 1, scale: 3.5 }}
transition={{ duration, ease: "easeOut" }}
onAnimationComplete={handleAnimationComplete}
style={{
top: ripple.y,
left: ripple.x,
width: "100%",
}}
/>
)}
</div>
);
}
API
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | - | The content or elements that are wrapped by the component. |
color | string (Tailwind CSS color class) | "bg-white" | The color of the ripple effect. Can be a Tailwind CSS color class such as bg-red-500 , bg-blue-300 . |
className | string | "" | Custom CSS classes for further styling or overriding default styles. |
duration | number | 0.6 | The duration of the ripple animation in seconds. |