DocumentationPerspective Grid

Perspective Grid

A stunning 3D perspective grid with colorful hover effects that responds to mouse movement.

Hover Me

Install using CLI

npx shadcn@latest add "https://vengeance-ui.vercel.app/r/perspective-grid.json"

Install Manually

1

Install dependencies

npm install clsx tailwind-merge
2

Add util file

lib/utils.ts

import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3

Add styles to global CSS

Add the following styles to your app/globals.css file

/* PerspectiveGrid Component Styles */
/* Base tile styles - ensure visibility */
.tile {
min-width: 1px;
min-height: 1px;
border-width: 1px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.2);
background-color: transparent;
box-sizing: border-box;
}
.dark .tile {
border-color: rgba(255, 255, 255, 0.15);
}
/* Hover colors */
.tile:nth-child(4n):hover {
background-color: rgb(248 113 113);
}
.tile:nth-child(4n + 1):hover {
background-color: rgb(56 189 248);
}
.tile:nth-child(4n + 2):hover {
background-color: rgb(74 222 128);
}
.tile:nth-child(4n + 3):hover {
background-color: rgb(253 224 71);
}
.tile:nth-child(7n):hover {
background-color: rgb(56 189 248);
}
.tile:nth-child(7n + 3):hover {
background-color: rgb(74 222 128);
}
.tile:nth-child(7n + 5):hover {
background-color: rgb(253 224 71);
}
.tile:nth-child(7n + 6):hover {
background-color: rgb(248 113 113);
}
.tile:nth-child(11n + 1):hover {
background-color: rgb(248 113 113);
}
.tile:nth-child(11n + 4):hover {
background-color: rgb(56 189 248);
}
.tile:nth-child(11n + 7):hover {
background-color: rgb(74 222 128);
}
.tile:nth-child(11n + 10):hover {
background-color: rgb(253 224 71);
}
4

Copy the source code

Copy the code below and paste it into components/ui/perspective-grid.tsx

"use client";
import React, { useEffect, useState, useMemo } from "react";
import { cn } from "@/lib/utils";
interface PerspectiveGridProps {
/** Additional CSS classes for the grid container */
className?: string;
/** Number of tiles per row/column (default: 40) */
gridSize?: number;
/** Whether to show the gradient overlay (default: true) */
showOverlay?: boolean;
/** Fade radius percentage for the gradient overlay (default: 80) */
fadeRadius?: number;
}
export function PerspectiveGrid({
className,
gridSize = 40,
showOverlay = true,
fadeRadius = 80,
}: PerspectiveGridProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
// Memoize tiles array to prevent unnecessary re-renders
const tiles = useMemo(() => Array.from({ length: gridSize * gridSize }), [gridSize]);
return (
<div
className={cn(
"relative w-full h-full overflow-hidden bg-white dark:bg-black",
"[--fade-stop:#ffffff] dark:[--fade-stop:#000000]",
className
)}
style={{
perspective: "2000px",
transformStyle: "preserve-3d",
}}
>
<div
className="absolute w-[80rem] aspect-square grid origin-center"
style={{
left: "50%",
top: "50%",
transform:
"translate(-50%, -50%) rotateX(30deg) rotateY(-5deg) rotateZ(20deg) scale(2)",
transformStyle: "preserve-3d",
gridTemplateColumns: `repeat(${gridSize}, 1fr)`,
gridTemplateRows: `repeat(${gridSize}, 1fr)`,
}}
>
{/* Tiles */}
{mounted &&
tiles.map((_, i) => (
<div
key={i}
className="tile min-h-[1px] min-w-[1px] border border-gray-300 dark:border-gray-700 bg-transparent transition-colors duration-[1500ms] hover:duration-0"
/>
))}
</div>
{/* Radial Gradient Mask (Overlay) */}
{showOverlay && (
<div
className="absolute inset-0 pointer-events-none z-10"
style={{
background: `radial-gradient(circle, transparent 25%, var(--fade-stop) ${fadeRadius}%)`,
}}
/>
)}
</div>
);
}
export default PerspectiveGrid;

Usage

1import { PerspectiveGrid } from "@/components/ui/perspective-grid"
2
3export function Example() {
4return (
5 <div className="relative h-[500px] w-full">
6 <PerspectiveGrid />
7 {/* Add your content on top */}
8 <div className="absolute inset-0 flex items-center justify-center z-20">
9 <h1>Your Content Here</h1>
10 </div>
11 </div>
12);
13}

Props

Prop NameTypeDefaultDescription
classNamestring-Additional CSS classes for the grid container.
gridSizenumber40Number of tiles per row/column (creates gridSize × gridSize tiles).
showOverlaybooleantrueWhether to show the gradient overlay.
fadeRadiusnumber80Fade radius percentage for the gradient overlay.

Features

3D Perspective: Realistic 3D grid with customizable perspective transform

Colorful Hover Effects: Tiles change to vibrant colors (red, cyan, green, yellow) on hover

Dark Mode Support: Seamlessly adapts to light and dark themes

Smooth Transitions: 1500ms transition duration with instant hover response

Gradient Fade: Radial gradient overlay for a polished look

Client-Side Rendering: Uses mounting state to prevent hydration issues