niceui

Animated Grid New

A perspective grid floor whose cells light up at random, faded with a radial mask.

ReactTailwind CSSTypeScriptEffectsMIT · Free
Live preview

Installation

01

Install with the shadcn CLI. The NiceUI theme comes along the first time.

$ npx shadcn@latest add https://niceui.dev/r/effects-animated-grid.json
02

Or copy the source below. Dependencies: none.

Source

components/niceui/effects/AnimatedGrid.tsx
import { useEffect, useState, type ReactNode } from 'react';
import { cn } from '@/lib/cn';

export type AnimatedGridProps = { cols?: number; rows?: number; interval?: number; children?: ReactNode; className?: string };

/** A perspective grid whose cells light up at random, faded with a radial mask. */
export function AnimatedGrid({ cols = 16, rows = 9, interval = 700, children, className }: AnimatedGridProps) {
  const total = cols * rows;
  const [lit, setLit] = useState<number[]>(() => Array.from({ length: 10 }, (_, i) => (i * 37) % total));
  useEffect(() => {
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    const id = window.setInterval(() => setLit((l) => [...l.slice(1), Math.floor(Math.random() * total)]), interval);
    return () => clearInterval(id);
  }, [interval, total]);
  return (
    <div className={cn('relative overflow-hidden rounded-2xl bg-ink-950', className)}>
      <div aria-hidden className="absolute inset-0 [perspective:700px]">
        <div
          className="absolute -inset-x-1/4 bottom-[-20%] top-[10%] grid [transform:rotateX(55deg)] [mask-image:radial-gradient(ellipse_at_center,black_20%,transparent_70%)]"
          style={{ gridTemplateColumns: `repeat(${cols}, 1fr)`, gridTemplateRows: `repeat(${rows}, 1fr)` }}
        >
          {Array.from({ length: total }, (_, i) => (
            <div key={i} className={cn('border-[0.5px] border-brand-300/15 transition-colors duration-1000', lit.includes(i) && 'bg-brand-400/40 shadow-[0_0_24px_rgba(56,189,248,0.5)]')} />
          ))}
        </div>
      </div>
      <div className="relative">{children}</div>
    </div>
  );
}

export function AnimatedGridDemo() {
  return (
    <AnimatedGrid className="flex min-h-[360px] w-full items-start justify-center px-6 pt-16 text-center">
      <div>
        <h3 className="text-4xl font-semibold tracking-tight text-white sm:text-5xl">Built on a grid.</h3>
        <p className="mx-auto mt-3 max-w-sm text-sm text-ink-400">Cells catch the light one by one, then fade back into the floor.</p>
      </div>
    </AnimatedGrid>
  );
}