Pixel grid loaderPro
A grid of rounded squares lighting in named patterns. CSS only, themed by text color, with a still frame for reduced motion.
On this page
Installation
Usage
import { PixelGridLoader } from "@/components/ui/chatcn/pro/pixel-grid-loader"
<PixelGridLoader pattern="spiral" grid={5} size="lg" />Cells are currentColor, so a text class sets the tone: text-chatcn-accent for the theme accent, text-chatcn-fg-subtle for a quiet one.
Examples
Every pattern
In context
Inside a button, a status row and an image slot, plus tones, sizes, paused and the reduced motion frame. In a right to left layout the grid mirrors, so sweeps and snakes start on the reading side.
Pending timing
Pending timing
Used as a pending state, a loader never shows in the first 300 ms: the user's own action is the feedback, and most waits end before that. Once shown, it stays at least 400 ms so it never flashes. useDelayedPresence from the free thinking-indicator does both.
import { useDelayedPresence } from "@/components/ui/chatcn/thinking-indicator"
const shown = useDelayedPresence(isPending)
{shown ? <PixelGridLoader /> : null}Patterns
| Pattern | How the light travels | Best grid |
|---|---|---|
snake | Row by row, turning at each end | 4 to 6 |
spiral | From the outer edge to the center | 5 to 8 |
sweep | A column passing across | 3 to 5 |
diagonal | A diagonal band from corner to corner | 4 to 6 |
pulse | Square rings growing from the center | 5 or 7 |
rain | Each column drops on its own beat | 5 to 8 |
scatter | Cells twinkle in a fixed random order | 5 to 8 |
orbit | A ring of cells turning around the center | 5 to 7 |
Props
| Prop | Type | Notes |
|---|---|---|
pattern | LoaderPattern | Default snake |
grid | 3 to 8 | Cells per side. Default 4 |
size | "xs" | "sm" | "md" | "lg" | "xl" | number | 14, 18, 24, 40 or 72 px, or any side length. Cells snap to whole pixels |
speed | number | Loop speed multiplier. Default 1 |
paused | boolean | Freezes the loop |
still | boolean | Draws the reduced motion frame |
label | string | Accessible name. Default "Loading"; "" hides it |
Keyboard
Not interactive: the loader takes no focus.
Accessibility
- The loader is
role="img"withlabelas its name, "Loading" by default. Next to a visible label, passlabel=""and it hides from assistive tech. - Announce the outcome, not the wait: put a polite live region on the result (Done, Failed) instead of on the loader.
- Under
prefers-contrast: moreunlit cells get darker; underforced-colorscells draw inCanvasText.
Motion
- Each cell lights at its place in the pattern and fades over a tail sized for the pattern, so the light reads as a head with a trail. Cells switch on instantly, like an LED, which keeps the motion crisp even at 0.25x.
- Under reduced motion the loop stops on one deterministic still frame and the whole loader breathes in opacity, 1 to 0.55 over 1.4 s, so it still reads as working without any movement.
stilldraws that frame on demand. pausedfreezes the loop where it is. Loaders are status, not decoration, so they need no pause button, but you can wire one topaused.- Animates only
opacityandtransform. No JavaScript runs per frame.