UI Components Easy
Animated Grid Pattern
An SVG grid pattern with randomly highlighted cells that pulse and glow, perfect for dark hero sections and backgrounds.
Open in Lab
MCP
css javascript vue svelte
Targets: TS JS HTML React Vue Svelte
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--glow-color: rgba(99, 102, 241, 0.6);
--glow-color-bright: rgba(129, 140, 248, 0.9);
--grid-line-color: rgba(255, 255, 255, 0.06);
--cell-size: 40px;
--glow-duration: 2.5s;
}
body {
font-family: system-ui, -apple-system, sans-serif;
min-height: 100vh;
background: #000;
overflow: hidden;
}
.grid-wrapper {
position: relative;
width: 100%;
height: 100vh;
display: grid;
place-items: center;
background: #0a0a0a;
overflow: hidden;
}
.grid-svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.grid-svg rect.cell {
fill: transparent;
stroke: var(--grid-line-color);
stroke-width: 0.5;
transition: fill 0.3s ease;
}
.grid-svg rect.cell.glow {
animation: cellGlow var(--glow-duration) ease-in-out forwards;
}
@keyframes cellGlow {
0% {
fill: transparent;
filter: drop-shadow(0 0 0 transparent);
}
20% {
fill: var(--glow-color);
filter: drop-shadow(0 0 8px var(--glow-color-bright));
}
50% {
fill: var(--glow-color-bright);
filter: drop-shadow(0 0 16px var(--glow-color-bright));
}
100% {
fill: transparent;
filter: drop-shadow(0 0 0 transparent);
}
}
.grid-fade {
position: absolute;
inset: 0;
background: radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%);
pointer-events: none;
}
.grid-content {
position: relative;
z-index: 10;
text-align: center;
color: #f1f5f9;
pointer-events: none;
}
.grid-title {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 800;
letter-spacing: -0.03em;
background: linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 0.5rem;
}
.grid-subtitle {
font-size: clamp(0.875rem, 2vw, 1.125rem);
color: rgba(148, 163, 184, 0.8);
font-weight: 400;
}// Animated Grid Pattern — randomly highlights grid cells with a glow effect
(function () {
"use strict";
const svg = document.getElementById("grid-svg");
if (!svg) return;
const CELL_SIZE = 40;
const GAP = 1;
const HIGHLIGHT_INTERVAL = 120;
const GLOW_DURATION = 2500;
const MAX_SIMULTANEOUS = 8;
let cols, rows;
const cells = [];
let activeCount = 0;
function buildGrid() {
const w = window.innerWidth;
const h = window.innerHeight;
cols = Math.ceil(w / (CELL_SIZE + GAP)) + 1;
rows = Math.ceil(h / (CELL_SIZE + GAP)) + 1;
svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
svg.innerHTML = "";
cells.length = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", c * (CELL_SIZE + GAP));
rect.setAttribute("y", r * (CELL_SIZE + GAP));
rect.setAttribute("width", CELL_SIZE);
rect.setAttribute("height", CELL_SIZE);
rect.setAttribute("rx", 2);
rect.classList.add("cell");
svg.appendChild(rect);
cells.push(rect);
}
}
}
function highlightRandom() {
if (cells.length === 0 || activeCount >= MAX_SIMULTANEOUS) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.classList.contains("glow")) return;
cell.classList.add("glow");
activeCount++;
setTimeout(() => {
cell.classList.remove("glow");
activeCount--;
}, GLOW_DURATION);
}
buildGrid();
setInterval(highlightRandom, HIGHLIGHT_INTERVAL);
let resizeTimer;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
activeCount = 0;
buildGrid();
}, 200);
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Animated Grid Pattern</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="grid-wrapper">
<svg id="grid-svg" class="grid-svg" aria-hidden="true"></svg>
<div class="grid-fade"></div>
<div class="grid-content">
<h1 class="grid-title">Animated Grid</h1>
<p class="grid-subtitle">Randomly glowing cells create a living background</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>import { useEffect, useRef, useCallback, useState } from "react";
interface AnimatedGridPatternProps {
cellSize?: number;
gap?: number;
glowColor?: string;
glowColorBright?: string;
highlightInterval?: number;
glowDuration?: number;
maxSimultaneous?: number;
className?: string;
}
export function AnimatedGridPattern({
cellSize = 40,
gap = 1,
glowColor = "rgba(99, 102, 241, 0.6)",
glowColorBright = "rgba(129, 140, 248, 0.9)",
highlightInterval = 120,
glowDuration = 2500,
maxSimultaneous = 8,
className = "",
}: AnimatedGridPatternProps) {
const svgRef = useRef<SVGSVGElement>(null);
const cellsRef = useRef<SVGRectElement[]>([]);
const activeCountRef = useRef(0);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const buildGrid = useCallback(() => {
const svg = svgRef.current;
if (!svg) return;
const parent = svg.parentElement;
if (!parent) return;
const w = parent.clientWidth;
const h = parent.clientHeight;
setDimensions({ width: w, height: h });
const cols = Math.ceil(w / (cellSize + gap)) + 1;
const rows = Math.ceil(h / (cellSize + gap)) + 1;
while (svg.firstChild) svg.removeChild(svg.firstChild);
cellsRef.current = [];
activeCountRef.current = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", String(c * (cellSize + gap)));
rect.setAttribute("y", String(r * (cellSize + gap)));
rect.setAttribute("width", String(cellSize));
rect.setAttribute("height", String(cellSize));
rect.setAttribute("rx", "2");
rect.setAttribute("fill", "transparent");
rect.setAttribute("stroke", "rgba(255,255,255,0.06)");
rect.setAttribute("stroke-width", "0.5");
svg.appendChild(rect);
cellsRef.current.push(rect);
}
}
}, [cellSize, gap]);
useEffect(() => {
buildGrid();
let resizeTimer: ReturnType<typeof setTimeout>;
const handleResize = () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildGrid, 200);
};
window.addEventListener("resize", handleResize);
return () => {
clearTimeout(resizeTimer);
window.removeEventListener("resize", handleResize);
};
}, [buildGrid]);
useEffect(() => {
const interval = setInterval(() => {
const cells = cellsRef.current;
if (cells.length === 0 || activeCountRef.current >= maxSimultaneous) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.dataset.active === "true") return;
cell.dataset.active = "true";
cell.setAttribute("fill", glowColor);
cell.style.filter = `drop-shadow(0 0 8px ${glowColorBright})`;
cell.style.transition = "fill 0.3s ease, filter 0.3s ease";
activeCountRef.current++;
setTimeout(() => {
cell.setAttribute("fill", glowColorBright);
cell.style.filter = `drop-shadow(0 0 16px ${glowColorBright})`;
}, glowDuration * 0.2);
setTimeout(() => {
cell.setAttribute("fill", "transparent");
cell.style.filter = "none";
cell.dataset.active = "false";
activeCountRef.current--;
}, glowDuration);
}, highlightInterval);
return () => clearInterval(interval);
}, [glowColor, glowColorBright, highlightInterval, glowDuration, maxSimultaneous]);
return (
<div
className={className}
style={{ position: "relative", width: "100%", height: "100%", overflow: "hidden" }}
>
<svg
ref={svgRef}
viewBox={`0 0 ${dimensions.width} ${dimensions.height}`}
style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}
aria-hidden="true"
/>
<div
style={{
position: "absolute",
inset: 0,
background: "radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%)",
pointerEvents: "none",
}}
/>
</div>
);
}
// Demo usage
export default function AnimatedGridPatternDemo() {
return (
<div
style={{
width: "100vw",
height: "100vh",
background: "#0a0a0a",
display: "grid",
placeItems: "center",
position: "relative",
}}
>
<AnimatedGridPattern
className=""
cellSize={40}
glowColor="rgba(99, 102, 241, 0.6)"
glowColorBright="rgba(129, 140, 248, 0.9)"
/>
<div
style={{
position: "relative",
zIndex: 10,
textAlign: "center",
pointerEvents: "none",
}}
>
<h1
style={{
fontSize: "clamp(2rem, 5vw, 3.5rem)",
fontWeight: 800,
letterSpacing: "-0.03em",
background: "linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%)",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
marginBottom: "0.5rem",
fontFamily: "system-ui, -apple-system, sans-serif",
}}
>
Animated Grid
</h1>
<p
style={{
fontSize: "clamp(0.875rem, 2vw, 1.125rem)",
color: "rgba(148, 163, 184, 0.8)",
fontFamily: "system-ui, -apple-system, sans-serif",
}}
>
Randomly glowing cells create a living background
</p>
</div>
</div>
);
}<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const props = defineProps({
cellSize: { type: Number, default: 40 },
gap: { type: Number, default: 1 },
glowColor: { type: String, default: "rgba(99, 102, 241, 0.6)" },
glowColorBright: { type: String, default: "rgba(129, 140, 248, 0.9)" },
highlightInterval: { type: Number, default: 120 },
glowDuration: { type: Number, default: 2500 },
maxSimultaneous: { type: Number, default: 8 },
});
const svgEl = ref(null);
const width = ref(0);
const height = ref(0);
let cells = [];
let activeCount = 0;
let intervalId;
let resizeTimer;
function buildGrid() {
const svg = svgEl.value;
if (!svg) return;
const parent = svg.parentElement;
if (!parent) return;
width.value = parent.clientWidth;
height.value = parent.clientHeight;
const cols = Math.ceil(width.value / (props.cellSize + props.gap)) + 1;
const rows = Math.ceil(height.value / (props.cellSize + props.gap)) + 1;
while (svg.firstChild) svg.removeChild(svg.firstChild);
cells = [];
activeCount = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", String(c * (props.cellSize + props.gap)));
rect.setAttribute("y", String(r * (props.cellSize + props.gap)));
rect.setAttribute("width", String(props.cellSize));
rect.setAttribute("height", String(props.cellSize));
rect.setAttribute("rx", "2");
rect.setAttribute("fill", "transparent");
rect.setAttribute("stroke", "rgba(255,255,255,0.06)");
rect.setAttribute("stroke-width", "0.5");
svg.appendChild(rect);
cells.push(rect);
}
}
}
function startHighlighting() {
intervalId = setInterval(() => {
if (cells.length === 0 || activeCount >= props.maxSimultaneous) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.dataset.active === "true") return;
cell.dataset.active = "true";
cell.setAttribute("fill", props.glowColor);
cell.style.filter = `drop-shadow(0 0 8px ${props.glowColorBright})`;
cell.style.transition = "fill 0.3s ease, filter 0.3s ease";
activeCount++;
setTimeout(() => {
cell.setAttribute("fill", props.glowColorBright);
cell.style.filter = `drop-shadow(0 0 16px ${props.glowColorBright})`;
}, props.glowDuration * 0.2);
setTimeout(() => {
cell.setAttribute("fill", "transparent");
cell.style.filter = "none";
cell.dataset.active = "false";
activeCount--;
}, props.glowDuration);
}, props.highlightInterval);
}
function handleResize() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildGrid, 200);
}
onMounted(() => {
buildGrid();
startHighlighting();
window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
clearInterval(intervalId);
clearTimeout(resizeTimer);
window.removeEventListener("resize", handleResize);
});
</script>
<template>
<div
style="width: 100vw; height: 100vh; background: #0a0a0a; display: grid; place-items: center; position: relative;"
>
<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">
<svg
ref="svgEl"
:viewBox="`0 0 ${width} ${height}`"
style="position: absolute; inset: 0; width: 100%; height: 100%;"
aria-hidden="true"
></svg>
<div
style="position: absolute; inset: 0; background: radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%); pointer-events: none;"
></div>
</div>
<div
style="position: absolute; z-index: 10; text-align: center; pointer-events: none;"
>
<h1
style="font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; background: linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 0.5rem; font-family: system-ui, -apple-system, sans-serif;"
>
Animated Grid
</h1>
<p
style="font-size: clamp(0.875rem, 2vw, 1.125rem); color: rgba(148, 163, 184, 0.8); font-family: system-ui, -apple-system, sans-serif;"
>
Randomly glowing cells create a living background
</p>
</div>
</div>
</template><script>
import { onMount, onDestroy } from "svelte";
export let cellSize = 40;
export let gap = 1;
export let glowColor = "rgba(99, 102, 241, 0.6)";
export let glowColorBright = "rgba(129, 140, 248, 0.9)";
export let highlightInterval = 120;
export let glowDuration = 2500;
export let maxSimultaneous = 8;
let svgEl;
let cells = [];
let activeCount = 0;
let width = 0;
let height = 0;
let intervalId;
let resizeTimer;
function buildGrid() {
if (!svgEl) return;
const parent = svgEl.parentElement;
if (!parent) return;
width = parent.clientWidth;
height = parent.clientHeight;
const cols = Math.ceil(width / (cellSize + gap)) + 1;
const rows = Math.ceil(height / (cellSize + gap)) + 1;
while (svgEl.firstChild) svgEl.removeChild(svgEl.firstChild);
cells = [];
activeCount = 0;
const ns = "http://www.w3.org/2000/svg";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const rect = document.createElementNS(ns, "rect");
rect.setAttribute("x", String(c * (cellSize + gap)));
rect.setAttribute("y", String(r * (cellSize + gap)));
rect.setAttribute("width", String(cellSize));
rect.setAttribute("height", String(cellSize));
rect.setAttribute("rx", "2");
rect.setAttribute("fill", "transparent");
rect.setAttribute("stroke", "rgba(255,255,255,0.06)");
rect.setAttribute("stroke-width", "0.5");
svgEl.appendChild(rect);
cells.push(rect);
}
}
}
function startHighlighting() {
intervalId = setInterval(() => {
if (cells.length === 0 || activeCount >= maxSimultaneous) return;
const idx = Math.floor(Math.random() * cells.length);
const cell = cells[idx];
if (cell.dataset.active === "true") return;
cell.dataset.active = "true";
cell.setAttribute("fill", glowColor);
cell.style.filter = `drop-shadow(0 0 8px ${glowColorBright})`;
cell.style.transition = "fill 0.3s ease, filter 0.3s ease";
activeCount++;
setTimeout(() => {
cell.setAttribute("fill", glowColorBright);
cell.style.filter = `drop-shadow(0 0 16px ${glowColorBright})`;
}, glowDuration * 0.2);
setTimeout(() => {
cell.setAttribute("fill", "transparent");
cell.style.filter = "none";
cell.dataset.active = "false";
activeCount--;
}, glowDuration);
}, highlightInterval);
}
function handleResize() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildGrid, 200);
}
onMount(() => {
buildGrid();
startHighlighting();
window.addEventListener("resize", handleResize);
});
onDestroy(() => {
clearInterval(intervalId);
clearTimeout(resizeTimer);
window.removeEventListener("resize", handleResize);
});
</script>
<div
style="width: 100vw; height: 100vh; background: #0a0a0a; display: grid; place-items: center; position: relative;"
>
<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">
<svg
bind:this={svgEl}
viewBox="0 0 {width} {height}"
style="position: absolute; inset: 0; width: 100%; height: 100%;"
aria-hidden="true"
></svg>
<div
style="position: absolute; inset: 0; background: radial-gradient(ellipse 50% 50% at 50% 50%, transparent 30%, #0a0a0a 80%); pointer-events: none;"
></div>
</div>
<div
style="position: absolute; z-index: 10; text-align: center; pointer-events: none;"
>
<h1
style="font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; background: linear-gradient(135deg, #e0e7ff 0%, #818cf8 50%, #6366f1 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 0.5rem; font-family: system-ui, -apple-system, sans-serif;"
>
Animated Grid
</h1>
<p
style="font-size: clamp(0.875rem, 2vw, 1.125rem); color: rgba(148, 163, 184, 0.8); font-family: system-ui, -apple-system, sans-serif;"
>
Randomly glowing cells create a living background
</p>
</div>
</div>Animated Grid Pattern
A mesmerizing SVG grid pattern where cells randomly highlight with a soft glow animation. Ideal as a subtle animated background for hero sections, dashboards, or landing pages.
How it works
- An SVG grid of rectangles is generated programmatically
- JavaScript randomly selects cells at intervals and adds a highlight class
- CSS keyframe animations handle the glow-in and fade-out transitions
- A radial gradient mask fades the grid edges for a polished look
Customization
- Adjust
COLS,ROWS,CELL_SIZE, andGAPto change the grid density - Modify the highlight color via the
--glow-colorCSS variable - Control animation speed with
--glow-durationand the JS interval timing
When to use it
- Hero section backgrounds
- Behind pricing or feature cards
- Dashboard ambient backgrounds
- Landing page visual accents