Eldora UI
Eldora UI
  1. Components
  2. Special Animations
  3. Spotlight card

Spotlight card

A spotlight effect with Tailwind CSS, good for drawing attention to a particular element on the page.

Card 01

Amazing Integration

Quickly apply filters to refine your issues lists and create custom views.

Connect
Card 02

Amazing Integration

Quickly apply filters to refine your issues lists and create custom views.

Connect
Card 03

Amazing Integration

Quickly apply filters to refine your issues lists and create custom views.

Connect
<Spotlightpage />

Installation

Copy and paste the following code into your project.

'use client'

import React, { useRef, useState, useEffect } from 'react'
import MousePosition from '../../utils/mouse-position'

type SpotlightProps = {
  children: React.ReactNode
  className?: string
}

export default function Spotlight({
  children,
  className = '',
}: SpotlightProps) {

  const containerRef = useRef<HTMLDivElement>(null)
  const mousePosition = MousePosition()
  const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 })
  const containerSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 })
  const [boxes, setBoxes] = useState<Array<HTMLElement>>([])

  useEffect(() => {    
    containerRef.current && setBoxes(Array.from(containerRef.current.children).map((el) => el as HTMLElement))
  }, [])
  
  useEffect(() => {    
    initContainer()
    window.addEventListener('resize', initContainer)

    return () => {
      window.removeEventListener('resize', initContainer)
    }
  }, [boxes])  

  useEffect(() => {
    onMouseMove()
  }, [mousePosition])

  const initContainer = () => {
    if(containerRef.current) {
      containerSize.current.w = containerRef.current.offsetWidth
      containerSize.current.h = containerRef.current.offsetHeight
    }
  }  
  
  const onMouseMove = () => {    
    if (containerRef.current) {
      const rect = containerRef.current.getBoundingClientRect()
      const { w, h } = containerSize.current
      const x = mousePosition.x - rect.left
      const y = mousePosition.y - rect.top
      const inside = x < w && x > 0 && y < h && y > 0      
      if (inside) {
        mouse.current.x = x
        mouse.current.y = y
        boxes.forEach((box) => {
          const boxX = -(box.getBoundingClientRect().left - rect.left) + mouse.current.x
          const boxY = -(box.getBoundingClientRect().top - rect.top) + mouse.current.y
          box.style.setProperty('--mouse-x', `${boxX}px`)
          box.style.setProperty('--mouse-y', `${boxY}px`)
        })
      }
    }
  }  

  return (
    <div className={className} ref={containerRef}>{children}</div>
  )
}

type SpotlightCardProps = {
  children: React.ReactNode,
  className?: string
}

export function SpotlightCard({
  children,
  className = ''
}: SpotlightCardProps) {
  return <div className={`relative h-full bg-slate-800 rounded-3xl p-px before:absolute before:w-80 before:h-80 before:-left-40 before:-top-40 before:bg-slate-400 before:rounded-full before:opacity-0 before:pointer-events-none before:transition-opacity before:duration-500 before:translate-x-[var(--mouse-x)] before:translate-y-[var(--mouse-y)] before:group-hover:opacity-100 before:z-10 before:blur-[100px] after:absolute after:w-96 after:h-96 after:-left-48 after:-top-48 after:bg-indigo-500 after:rounded-full after:opacity-0 after:pointer-events-none after:transition-opacity after:duration-500 after:translate-x-[var(--mouse-x)] after:translate-y-[var(--mouse-y)] after:hover:opacity-10 after:z-30 after:blur-[100px] overflow-hidden ${className}`}>{children}</div>
}

Add this utils file utils/mouse-position.ts.

import { useState, useEffect } from 'react';

interface MousePosition {
x: number;
y: number;
}

export default function useMousePosition(): MousePosition {
const [mousePosition, setMousePosition] = useState<MousePosition>({ x: 0, y: 0 });

useEffect(() => {
  const handleMouseMove = (event: MouseEvent) => {
    setMousePosition({ x: event.clientX, y: event.clientY });
  }

  window.addEventListener('mousemove', handleMouseMove);

  return () => {
    window.removeEventListener('mousemove', handleMouseMove);
  }
}, []);

return mousePosition;
}

Update the import paths to match your project setup.

Props

Spotlight component Props

Prop NameTypeDefaultDescription
children
React.ReactNode
none
Content to be rendered inside the spotlight container.
className
string
''
Additional classes for styling the spotlight container.

SpotlightCard Component Props

Prop NameTypeDefaultDescription
children
React.ReactNode
none
Content to be rendered inside the spotlight card.
className
string
''
Additional classes for styling the spotlight card.

Built by karthikmudunuri. The source code is available on GitHub.