Cursor Spotlight
A darkened section where only the area near your cursor is revealed — like sweeping a flashlight across the page
cursorspotlightflashlightrevealinteractive
Install dependencies
$npm install framer-motionPreview
Source Code
"use client";
import { useRef } from "react";
import {
motion,
useMotionTemplate,
useMotionValue,
useReducedMotion,
useSpring,
} from "framer-motion";
interface CursorSpotlightProps {
children?: React.ReactNode;
size?: number;
overlayColor?: string;
className?: string;
}
export default function CursorSpotlight({
children,
size = 180,
overlayColor = "rgba(5, 6, 12, 0.93)",
className = "",
}: CursorSpotlightProps) {
const ref = useRef<HTMLDivElement>(null);
const reduceMotion = useReducedMotion();
const x = useMotionValue(0);
const y = useMotionValue(0);
const radius = useMotionValue(0);
const springConfig = reduceMotion
? { stiffness: 2000, damping: 90 }
: { stiffness: 150, damping: 20 };
const sx = useSpring(x, springConfig);
const sy = useSpring(y, springConfig);
const sr = useSpring(radius, { stiffness: 200, damping: 25 });
const overlay = useMotionTemplate`radial-gradient(circle ${sr}px at ${sx}px ${sy}px, transparent 30%, ${overlayColor} 100%)`;
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
x.set(e.clientX - rect.left);
y.set(e.clientY - rect.top);
radius.set(size);
};
return (
<div
ref={ref}
onMouseMove={handleMouseMove}
onMouseLeave={() => radius.set(0)}
className={`relative overflow-hidden bg-[#05060c] ${className}`}
>
{children}
<motion.div
aria-hidden="true"
className="pointer-events-none absolute inset-0 z-10"
style={{ background: overlay }}
/>
</div>
);
}