Spotlight
A dynamic spotlight effect component that follows cursor movement.
Examples
Spotlight Basic 1
Spotlight Custom Color
You can customize the color with using Tailwind CSS gradient color stop. (e.g from-blue-800 via-blue-600 to-blue-400
)
Spotlight Border
You can create a spotlight border by creating a container with a padding that will be used as a border.
Code
'use client';
import React, { useRef, useState, useCallback, useEffect } from 'react';
import { motion, useSpring, useTransform, SpringOptions } from 'framer-motion';
import { cn } from '@/lib/utils';
type SpotlightProps = {
className?: string;
size?: number;
springOptions?: SpringOptions;
};
export function Spotlight({
className,
size = 200,
springOptions = { bounce: 0 },
}: SpotlightProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [isHovered, setIsHovered] = useState(false);
const [parentElement, setParentElement] = useState<HTMLElement | null>(null);
const mouseX = useSpring(0, springOptions);
const mouseY = useSpring(0, springOptions);
const spotlightLeft = useTransform(mouseX, (x) => `${x - size / 2}px`);
const spotlightTop = useTransform(mouseY, (y) => `${y - size / 2}px`);
useEffect(() => {
if (containerRef.current) {
const parent = containerRef.current.parentElement;
if (parent) {
parent.style.position = 'relative';
parent.style.overflow = 'hidden';
setParentElement(parent);
}
}
}, []);
const handleMouseMove = useCallback(
(event: MouseEvent) => {
if (!parentElement) return;
const { left, top } = parentElement.getBoundingClientRect();
mouseX.set(event.clientX - left);
mouseY.set(event.clientY - top);
},
[mouseX, mouseY, parentElement]
);
useEffect(() => {
if (!parentElement) return;
parentElement.addEventListener('mousemove', handleMouseMove);
parentElement.addEventListener('mouseenter', () => setIsHovered(true));
parentElement.addEventListener('mouseleave', () => setIsHovered(false));
return () => {
parentElement.removeEventListener('mousemove', handleMouseMove);
parentElement.removeEventListener('mouseenter', () => setIsHovered(true));
parentElement.removeEventListener('mouseleave', () =>
setIsHovered(false)
);
};
}, [parentElement, handleMouseMove]);
return (
<motion.div
ref={containerRef}
className={cn(
'pointer-events-none absolute rounded-full bg-[radial-gradient(circle_at_center,var(--tw-gradient-stops),transparent_80%)] blur-xl transition-opacity duration-200',
'from-zinc-50 via-zinc-100 to-zinc-200',
isHovered ? 'opacity-100' : 'opacity-0',
className
)}
style={{
width: size,
height: size,
left: spotlightLeft,
top: spotlightTop,
}}
/>
);
}
Please add:
Component API
Spotlight
Prop | Type | Default | Description |
---|---|---|---|
className | string | '' | Additional CSS classes for styling |
size | number | 200 | Size of the spotlight effect in pixels |
springOptions | SpringOptions | { bounce: 0 } | Animation spring configuration |
Credit
Initiated by @divyanshu-vashishth