Back

GridLoader

a customizable 3x3 grid loader with 10 terminal-aesthetic animation variants. sharp on/off blink patterns — click any variant below to view its standalone source code.

GitHub
Install
npm install react-grid-loader
Usage
import { GridLoader } from "react-grid-loader";
import "react-grid-loader/styles.css";

export function MyComponent() {
  return <GridLoader variant="spiral" color="#ffffff" size={40} speed={1.2} />;
}
Props
PropTypeDefaultDescription
variantVariant"spiral"Animation pattern
colorstring"#ffffff"Square color
sizenumber40Overall size in px
speednumber1.2Animation duration in seconds
gapnumber4Gap between squares in px
Standalone source — spiral

Zero-dependency, copy-paste ready. Click a variant above to switch.

import React, { useEffect } from "react";

interface SpiralLoaderProps {
  color?: string;
  size?: number;
  speed?: number;
  gap?: number;
}

const DELAYS = [0, 1, 2, 7, 8, 3, 6, 5, 4];
const STYLE_ID = "gridloader-sq-spiral";

const CSS = `
.gridloader-sq-spiral-square {
  animation: gridloader-sq-spiral-blink var(--gl-speed, 1.2s) steps(1, end) infinite both;
  opacity: 0.08;
}
@keyframes gridloader-sq-spiral-blink {
  0%, 100% { opacity: 0.08; }
  30%, 60% { opacity: 1; }
}`;

export function SpiralLoader({
  color = "#ffffff",
  size = 40,
  speed = 1.2,
  gap = 4,
}: SpiralLoaderProps) {
  useEffect(() => {
    if (!document.getElementById(STYLE_ID)) {
      const style = document.createElement("style");
      style.id = STYLE_ID;
      style.textContent = CSS;
      document.head.appendChild(style);
    }
  }, []);

  const sq = (size - gap * 2) / 3;
  const maxOrder = Math.max(...DELAYS);
  const delays = DELAYS.map((o) => (o / maxOrder) * speed * 0.8);

  return (
    <div
      role="status"
      aria-label="Loading"
      style={{
        display: "grid",
        gridTemplateColumns: `repeat(3, ${sq}px)`,
        gridTemplateRows: `repeat(3, ${sq}px)`,
        gap: `${gap}px`,
        width: `${size}px`,
        height: `${size}px`,
        ["--gl-speed" as string]: `${speed}s`,
      }}
    >
      {delays.map((delay, i) => (
        <div
          key={i}
          className="gridloader-sq-spiral-square"
          style={{
            backgroundColor: color,
            animationDelay: `${delay}s`,
          }}
        />
      ))}
    </div>
  );
}