🎯 Hover Grid

An interactive grid component that creates smooth hover animations with gradient highlights following mouse movement. Perfect for showcasing skills, technologies, or any categorized content with engaging visual feedback.

( REACTJS )

( NEXTJS )

( JAVASCRIPT )

( TYPESCRIPT )

( GSAP )

( MOTION.DEV )

( TAILWIND )

Install Dependencies

npm i motion

Code

HoverGrid.tsx

"use client";
import { useState } from "react";
import { motion } from "motion/react";

interface HoverGridProps {
  items?: string[];
  highlightGradients?: string[];
}

export default function HoverGrid({
  items = [
    "( HTML )",
    "( CSS )",
    "( JAVASCRIPT )",
    "( GSAP )",
    "( SCROLLTRIGGER )",
    "( REACT )",
    "( THREE.JS )",
  ],
  highlightGradients = [
    "linear-gradient(135deg, #E24E1B, #F6A623)",
    "linear-gradient(135deg, #4381C1, #5BB5F0)",
    "linear-gradient(135deg, #F79824, #FFD54F)",
    "linear-gradient(135deg, #04A777, #4DD599)",
    "linear-gradient(135deg, #5B8C5A, #A8E6CF)",
    "linear-gradient(135deg, #2176FF, #33A1FD)",
    "linear-gradient(135deg, #818D92, #B0BEC5)",
  ],
}: HoverGridProps) {
  const [highlightStyle, setHighlightStyle] = useState({
    x: 0,
    y: 0,
    width: 0,
    height: 0,
    gradient: highlightGradients[0],
  });

  const handleHover = (
    e: React.MouseEvent<HTMLDivElement, MouseEvent>,
    index: number
  ) => {
    const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();
    setHighlightStyle({
      x:
        rect.left -
        (e.currentTarget.offsetParent as HTMLElement).getBoundingClientRect()
          .left,
      y:
        rect.top -
        (e.currentTarget.offsetParent as HTMLElement).getBoundingClientRect()
          .top,
      width: rect.width,
      height: rect.height,
      gradient: highlightGradients[index % highlightGradients.length],
    });
  };

  return (
    <div className="w-full min-h-screen bg-neutral-900 flex items-center justify-center px-4 py-10">
      {/* Desktop & Tablet */}
      <div className="hidden sm:block relative w-4/5 border border-white/20 overflow-hidden rounded-xl">
        <motion.div
          className="absolute pointer-events-none z-0 "
          style={{ background: highlightStyle.gradient }}
          animate={{
            x: highlightStyle.x,
            y: highlightStyle.y,
            width: highlightStyle.width,
            height: highlightStyle.height,
          }}
          transition={{ type: "spring", stiffness: 250, damping: 25 }}
        />

        {/* Row 1 */}
        <div className="flex border-b border-white/20">
          {items.slice(0, 3).map((label, idx) => (
            <div
              key={label}
              className="flex-1 flex items-center justify-center border-r last:border-r-0 border-white/20 cursor-pointer relative z-10 py-20"
              onMouseEnter={(e) => handleHover(e, idx)}
            >
              <p className="uppercase text-white text-sm font-medium">
                {label}
              </p>
            </div>
          ))}
        </div>

        {/* Row 2 */}
        <div className="flex">
          {items.slice(3).map((label, idx) => (
            <div
              key={label}
              className="flex-1 flex items-center justify-center border-r last:border-r-0 border-white/20 cursor-pointer relative z-10 py-20 border-t"
              onMouseEnter={(e) => handleHover(e, idx + 3)}
            >
              <p className="uppercase text-white text-sm font-medium">
                {label}
              </p>
            </div>
          ))}
        </div>
      </div>

      {/* Mobile */}
      <div className="grid grid-cols-2 sm:hidden gap-4 w-full max-w-md">
        {items.map((label, idx) => (
          <div
            key={idx}
            className="bg-neutral-800 text-white  py-10 flex items-center justify-center"
          >
            <p className="uppercase text-sm font-medium">{label}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

Props

PropTypeDefaultDescription
itemsstring[]Tech stack itemsArray of text items to display in the grid
highlightGradientsstring[]Default gradientsArray of CSS gradient strings for hover highlights

Customization

Grid Layout: The component automatically arranges items in a 2-row layout:

  • First 3 items in the top row
  • Remaining items in the bottom row

Animation Settings:

// Modify the spring animation
transition={{ 
  type: "spring", 
  stiffness: 250,  // Higher = snappier
  damping: 25      // Higher = less bouncy
}}
Hover Grid16