Docs
Cursor Spotlight

Cursor Spotlight

An interactive component with a cursor-following spotlight effect that reveals background elements

M3
N7
O7
P4
Q2
R5
E3
F3
G2
H3
I9
J1

Explore the Grid

Move your cursor across the canvas to reveal a modern design system. Each element represents a component in our design language.

Installation

Copy and paste the following code into your project.

"use client";
 
import React, { useRef, useState } from "react";
import { cn } from "@/lib/utils";
 
export interface CursorSpotlightProps
  extends React.HTMLAttributes<HTMLDivElement> {
  children?: React.ReactNode;
  backgroundContent: React.ReactNode;
  spotlightSize?: number;
  overlayOpacity?: number;
  spotlightColor?: string;
  blurredEdges?: boolean;
  showFaintBackground?: boolean;
  glowIntensity?: number;
  noiseTexture?: boolean;
}
 
export function CursorSpotlight({
  children,
  className,
  backgroundContent,
  spotlightSize = 50,
  overlayOpacity = 0.9,
  spotlightColor = "rgba(255, 255, 255, 0.15)",
  blurredEdges = true,
  showFaintBackground = false,
  glowIntensity = 0.2,
  noiseTexture = true,
  ...props
}: CursorSpotlightProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [position, setPosition] = useState<{ x: number; y: number }>({
    x: -1000,
    y: -1000,
  });
  const [isHovering, setIsHovering] = useState(false);
 
  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
    if (!containerRef.current) return;
 
    const rect = containerRef.current.getBoundingClientRect();
    setPosition({
      x: e.clientX - rect.left,
      y: e.clientY - rect.top,
    });
  };
 
  const handleMouseEnter = () => {
    setIsHovering(true);
  };
 
  const handleMouseLeave = () => {
    setIsHovering(false);
    setPosition({
      x: -1000,
      y: -1000,
    });
  };
 
  const getSpotlightGradient = () => {
    const blurAmount = blurredEdges ? "circle" : "circle";
    return `radial-gradient(${spotlightSize}px ${blurAmount} at ${position.x}px ${position.y}px, 
      transparent 0%, 
      rgba(0, 0, 0, ${overlayOpacity}) ${blurredEdges ? "80%" : "100%"})`;
  };
 
  const getGlowEffect = () => {
    return `radial-gradient(${spotlightSize * 1.2}px circle at ${position.x}px ${position.y}px, 
      ${spotlightColor} 0%, 
      transparent 70%)`;
  };
 
  return (
    <div
      ref={containerRef}
      className={cn("relative overflow-hidden", className)}
      onMouseMove={handleMouseMove}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
      {...props}
    >
      <div className="absolute inset-0 z-0">{backgroundContent}</div>
 
      <div
        className="absolute inset-0 z-10 transition-opacity duration-300"
        style={{
          background: getSpotlightGradient(),
          opacity: 1,
          pointerEvents: "none",
        }}
      />
 
      {glowIntensity > 0 && (
        <div
          className="absolute inset-0 z-20 mix-blend-overlay transition-opacity duration-300"
          style={{
            background: getGlowEffect(),
            opacity: isHovering ? glowIntensity : 0,
            pointerEvents: "none",
          }}
        />
      )}
 
      {noiseTexture && (
        <div
          className="absolute inset-0 z-30 opacity-20 pointer-events-none mix-blend-overlay"
          style={{
            opacity: isHovering ? 0.1 : 0,
          }}
        >
          <svg
            className="h-full w-full opacity-20"
            xmlns="http://www.w3.org/2000/svg"
            width="100%"
            height="100%"
          >
            <filter id="noise">
              <feTurbulence
                type="fractalNoise"
                baseFrequency="0.65"
                numOctaves="3"
                stitchTiles="stitch"
              />
              <feColorMatrix type="saturate" values="0" />
            </filter>
            <rect width="100%" height="100%" filter="url(#noise)" />
          </svg>
        </div>
      )}
 
      {showFaintBackground && (
        <div
          className="absolute inset-0 z-5 transition-opacity duration-300"
          style={{
            background: `rgba(0, 0, 0, ${overlayOpacity * 0.7})`,
            opacity: 1,
            pointerEvents: "none",
          }}
        />
      )}
 
      <div className="relative z-40">{children}</div>
    </div>
  );
}

Update the import paths to match your project setup.

import CursorSpotlight from "@/components/ui/cursor-spotlight";

Usage

import CursorSpotlight from "@/components/ui/cursor-spotlight";
 
export default function MyComponent() {
  return (
    <CursorSpotlight
      className="h-[500px] w-full rounded-xl"
      spotlightSize={200}
      overlayOpacity={0.95}
      spotlightColor="rgba(100, 100, 255, 0.2)"
      backgroundContent={
        <div className="grid h-full w-full grid-cols-4 grid-rows-4 gap-4 p-8">
          {/* Your background elements here */}
        </div>
      }
    >
      <div className="flex h-full w-full flex-col items-center justify-center p-8 text-center">
        <h2 className="text-3xl font-bold">Move your cursor to reveal</h2>
        <p className="mt-4 text-muted-foreground">
          Content visible on top of the spotlight effect
        </p>
      </div>
    </CursorSpotlight>
  );
}

Props

PropTypeDescriptionDefault
backgroundContentReact.ReactNodeBackground elements to be revealed by the spotlightRequired
childrenReact.ReactNodeContent to display on top of the spotlight effect-
spotlightSizenumberSize of the spotlight circle in pixels250
overlayOpacitynumberOpacity of the overlay covering the background (0-1)0.9
spotlightColorstringColor of the spotlight effectrgba(255, 255, 255, 0.15)
blurredEdgesbooleanWhether to add a blur effect to the spotlight edgestrue
showFaintBackgroundbooleanWhether to show a faint version of the background outside the spotlightfalse
glowIntensitynumberIntensity of the glow effect (0-1)0.2
noiseTexturebooleanWhether to add a subtle noise texture to the overlaytrue

Examples

Basic Example

<CursorSpotlight
  className="h-[400px] w-full rounded-xl"
  spotlightSize={150}
  backgroundContent={
    <div className="grid h-full w-full grid-cols-3 grid-rows-3 gap-2 p-4">
      {/* Your background elements */}
    </div>
  }
>
  <div className="flex h-full items-center justify-center">
    <h2 className="text-2xl font-bold">Explore with your cursor</h2>
  </div>
</CursorSpotlight>

With Colored Spotlight

<CursorSpotlight
  className="h-[400px] w-full rounded-xl"
  spotlightSize={200}
  spotlightColor="rgba(255, 100, 100, 0.2)"
  glowIntensity={0.4}
  backgroundContent={
    <div className="grid h-full w-full grid-cols-3 grid-rows-3 gap-2 p-4">
      {/* Your background elements */}
    </div>
  }
>
  <div className="flex h-full items-center justify-center">
    <h2 className="text-2xl font-bold">Red spotlight effect</h2>
  </div>
</CursorSpotlight>

With Faint Background

<CursorSpotlight
  className="h-[400px] w-full rounded-xl"
  spotlightSize={180}
  showFaintBackground={true}
  backgroundContent={
    <div className="grid h-full w-full grid-cols-3 grid-rows-3 gap-2 p-4">
      {/* Your background elements */}
    </div>
  }
>
  <div className="flex h-full items-center justify-center">
    <h2 className="text-2xl font-bold">Faintly visible background</h2>
  </div>
</CursorSpotlight>