Glowing Dots Background
A background with dots that light up when you hover over them. Creates an interactive grid of glowing elements.
Install dependencies
npm i framer-motion
Component
Create a file glowing-dots-background.tsx in your components folder and paste this code
'use client';
import React, { useEffect, useRef, useState } from 'react';
import { motion } from 'framer-motion';
type GlowingDotsBackgroundProps = {
children?: React.ReactNode;
className?: string;
diameter?: number;
fadeDelay?: number;
};
const getRandomColor = () => {
const colors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A8', '#FFD700', '#00FFFF'];
return `${colors[Math.floor(Math.random() * colors.length)]}77`;
};
const GlowingDotsBackground = ({
children,
className,
diameter = 10,
fadeDelay = 350
}: GlowingDotsBackgroundProps) => {
const divRef = useRef<HTMLDivElement>(null);
const activeCells = useRef<Set<number>>(new Set());
const [gridSize, setGridSize] = useState({ cols: 0, rows: 0 });
const [hoveredCells, setHoveredCells] = useState<number[]>([]);
useEffect(() => {
if (!divRef.current) return;
const updateGridSize = () => {
const height = divRef.current!.offsetHeight;
const width = divRef.current!.offsetWidth;
setGridSize({
rows: Math.ceil(height / diameter),
cols: Math.ceil(width / diameter)
});
};
updateGridSize();
window.addEventListener('resize', updateGridSize);
return () => window.removeEventListener('resize', updateGridSize);
}, []);
const handleMouseEnter = (index: number) => {
if (activeCells.current.has(index)) return;
activeCells.current.add(index);
setHoveredCells((prev) => [...prev, index]);
setTimeout(() => {
activeCells.current.delete(index);
setHoveredCells((prev) => prev.filter((i) => i !== index));
}, fadeDelay);
};
return (
<div ref={divRef} className="h-full w-full flex items-center justify-center relative bg-black">
<div
id="glowing-dots-background"
style={{
gridTemplateColumns: `repeat(${gridSize.cols}, ${diameter}px)`
}}
className="grid overflow-hidden h-full w-full"
>
{Array(gridSize.rows * gridSize.cols)
.fill(null)
.map((_, i) => (
<motion.div
key={'box' + i}
onMouseEnter={() => handleMouseEnter(i)}
animate={{
boxShadow: hoveredCells.includes(i) ? `1px 1px 20px 2px ${getRandomColor()}` : ''
}}
transition={{ duration: 0.3 }}
className={`h-[${diameter}px] w-[${diameter}px] border-[1px] rounded-full border-zinc-900/0`}
/>
))}
</div>
{/* <div
style={{ background: 'radial-gradient(circle at center, transparent, #000000)' }}
className="h-full w-full absolute pointer-events-none"
/> */}
<div
className={`h-full w-full flex items-center pointer-events-none justify-center absolute top-0 left-0 ${className}`}
>
{children}
</div>
</div>
);
};
export default GlowingDotsBackground;
Usage
<GlowingDotsBackground
diameter={80}
className=" text-5xl font-extrabold text-white rounded-xl flex items-center justify-center h-full w-full"
>
Glowing Dots Background
</GlowingDotsBackground>