
Component Structure
The component uses Next.js Image optimization for the background, React state for input management, and a ref to handle the ripple effect positioning:
const ZipCodeChecker = () => {
const [zipCode, setZipCode] = useState('');
const imageWrapperRef = useRef<HTMLDivElement>(null);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Handle zip code validation
};
return (
<div ref={imageWrapperRef} className="relative overflow-hidden rounded-2xl">
<Image
src="/your-background-image.jpg"
alt="Background"
width={1200}
height={600}
className="object-cover"
/>
<form onSubmit={handleSubmit} className="absolute inset-0 flex flex-col items-center justify-center">
<input
type="text"
value={zipCode}
onChange={(e) => setZipCode(e.target.value)}
placeholder="Enter zip code"
className="px-4 py-2 rounded-lg"
/>
<button
onClick={createRipple}
className="mt-4 px-6 py-3 bg-blue-600 text-white rounded-lg"
>
Check Availability
</button>
</form>
</div>
);
};
Ripple Click Effect
To create the ripple click effect, I use a DOM reference. This allows me to insert a temporary element exactly where the user clicks, without adding extra markup.
When the Check Availability button is clicked, a ripple is created and positioned using the mouse coordinates and the container's bounds:
const createRipple = (e: React.MouseEvent<HTMLButtonElement>) => {
const button = e.currentTarget;
const wrapper = imageWrapperRef.current;
if (!wrapper) return;
const ripple = document.createElement('span');
const rect = wrapper.getBoundingClientRect();
ripple.style.left = `${e.clientX - rect.left}px`;
ripple.style.top = `${e.clientY - rect.top}px`;
ripple.classList.add('ripple');
wrapper.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
};
The ripple element is dynamically created, positioned at the click coordinates relative to the container, and then removed after the animation completes.
Ripple Animation CSS
The ripple effect is achieved through CSS animations that scale and fade the element:
.ripple {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
width: 100px;
height: 100px;
margin-top: -50px;
margin-left: -50px;
animation: ripple-effect 0.6s ease-out;
pointer-events: none;
}
@keyframes ripple-effect {
0% {
transform: scale(0);
opacity: 1;
}
100% {
transform: scale(4);
opacity: 0;
}
}
The animation scales the ripple from 0 to 4x its size while fading it out, creating a smooth, water-like expansion effect. The pointer-events: none ensures it doesn't interfere with other interactions.
Key Features
- Optimized background image using Next.js Image component
- Dynamic ripple effect triggered on button click
- Clean, centered layout with Tailwind CSS
- Responsive design that adapts to different screen sizes
- Easy to extend with real API validation logic
Here's the source code, I hope you like it :)
prash240303/crafts/ZipCodeChecker