22

Card Spotlight

A Card Spotlight component for Next.js, built with React and styled using TailwindCSS.

Card Spotlight Component

This interactive component features a dynamic spotlight that follows the user's cursor, highlighting elements on the card. It's built using the CardSpotlight component in your Next.js application, leveraging React for reactive features and TailwindCSS for seamless styling.

Card Content

Usage

To use the CardSpotlight component in your project, simply import it from where it is defined:

import CardSpotlight from "@/app/components/CardSpotlight";
 
function MyApp() {
  return <CardSpotlight />;
}

Source Code

Create the CardSpotlight component in @/app/components/CardSpotlight.tsx with the following structure:

"use client";
import type React from "react";
import { useRef, useState, useCallback } from "react";
 
interface Position {
  x: number;
  y: number;
}
 
const CardSpotlight: React.FC = () => {
  const divRef = useRef<HTMLDivElement>(null);
  const [isFocused, setIsFocused] = useState(false);
  const [position, setPosition] = useState<Position>({ x: 0, y: 0 });
  const [opacity, setOpacity] = useState(0);
 
  const handleMouseMove = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      if (!divRef.current || isFocused) return;
 
      const rect = divRef.current.getBoundingClientRect();
      setPosition({
        x: e.clientX - rect.left,
        y: e.clientY - rect.top,
      });
    },
    [isFocused]
  );
 
  const handleFocus = useCallback(() => {
    setIsFocused(true);
    setOpacity(1);
  }, []);
 
  const handleBlur = useCallback(() => {
    setIsFocused(false);
    setOpacity(0);
  }, []);
 
  const handleMouseEnter = useCallback(() => setOpacity(1), []);
  const handleMouseLeave = useCallback(() => setOpacity(0), []);
 
  return (
    <div
      ref={divRef}
      onMouseMove={handleMouseMove}
      onFocus={handleFocus}
      onBlur={handleBlur}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
      className="relative flex h-48 w-48 items-center justify-center overflow-hidden rounded-xl border border-zinc-800 bg-gradient-to-r from-black to-zinc-950 px-8 py-16 shadow-2xl"
    >
      <div
        className="pointer-events-none absolute -inset-px opacity-0 transition duration-300"
        style={{
          opacity,
          background: `radial-gradient(600px circle at ${position.x}px ${position.y}px, rgba(255,255,255,0.2), transparent 40%)`,
        }}
      />
      <p className="text-sm text-zinc-200">Card Content</p>
    </div>
  );
};
 
export default CardSpotlight;