Spotlight Card
Card with cursor-tracking spotlight glow on border and surface
cardspotlightglowinteractivehover
Preview
Source Code
"use client";
import { useRef, useState } from "react";
interface SpotlightCardProps {
children: React.ReactNode;
className?: string;
spotlightColor?: string;
}
export default function SpotlightCard({
children,
className = "",
spotlightColor = "rgba(99,102,241,0.4)",
}: SpotlightCardProps) {
const ref = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState({ x: 0, y: 0 });
const [isHovered, setIsHovered] = useState(false);
const handleMouseMove = (e: React.MouseEvent) => {
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
setPosition({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
});
};
return (
<div
ref={ref}
onMouseMove={handleMouseMove}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
className={`relative overflow-hidden rounded-2xl border border-white/15 bg-gray-900 ${className}`}
>
{/* Spotlight glow that follows cursor */}
<div
className="pointer-events-none absolute -inset-px rounded-2xl transition-opacity duration-300"
style={{
opacity: isHovered ? 1 : 0,
background: `radial-gradient(600px circle at ${position.x}px ${position.y}px, ${spotlightColor}, transparent 40%)`,
}}
/>
{/* Border glow that follows cursor */}
<div
className="pointer-events-none absolute -inset-px rounded-2xl transition-opacity duration-300"
style={{
opacity: isHovered ? 1 : 0,
background: `radial-gradient(300px circle at ${position.x}px ${position.y}px, ${spotlightColor}, transparent 40%)`,
mask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
maskComposite: "exclude",
WebkitMaskComposite: "xor",
padding: "1px",
}}
/>
<div className="relative z-10">{children}</div>
</div>
);
}