Accessible React loading states designed for generative interfaces: sixteen animated text reveals, eighteen compact activity indicators, and twelve image-generation placeholders.
Live gallery · Documentation · npm · Report an issue
npm install generative-loadersThe package supports React 18 and newer.
Import the component you need and include the stylesheet once near your application root.
import { ImageLoader, InlineLoader, TextLoader } from "generative-loaders";
import "generative-loaders/styles.css";
export function GeneratingAnswer({ text }: { text: string }) {
return <TextLoader text={text} variant="decode" />;
}
export function PendingStatus() {
return <span><InlineLoader variant="orbit" /> Thinking…</span>;
}
export function PendingImage() {
return <ImageLoader variant="tiles" size={192} label="Generating product image" />;
}| Component | Use it for | Included variants |
|---|---|---|
TextLoader |
Responses that grow as tokens or chunks arrive | 16 |
InlineLoader |
Buttons, status rows, and the wait before text arrives | 18 |
ImageLoader |
Reserved image frames while generation is in progress | 12 |
Pass the complete response received so far—not only the newest token. TextLoader keeps the existing prefix stable and animates only the newly appended suffix.
"use client";
import { useState } from "react";
import { TextLoader } from "generative-loaders";
import "generative-loaders/styles.css";
export function StreamingAnswer() {
const [text, setText] = useState("");
async function generate() {
setText("");
const response = await fetch("/api/generate", { method: "POST" });
if (!response.ok || !response.body) throw new Error("Generation failed");
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
setText((current) => current + decoder.decode(value, { stream: true }));
}
}
return <TextLoader text={text} variant="cascade" />;
}Text: decode, typewriter, skeleton, cascade, focus, wipe, flip, redact, line, terminal, wave, dissolve, slice, tracking, coalesce, fragments
Inline: glyph, matrix, orbit, ripple, signal, spark, rotor, pixel-drift, chomp, snake, fold, gravity, domino, aperture, dot-pulse, vortex, halo, count-up
Image: skeleton, bands, tiles, scan, pixel-grid, resolution, coalesce, diffusion, raster, bloom, focus, shutter
See every variant, speed control, and usage context in the live gallery.
| Prop | Type | Default |
|---|---|---|
text |
string |
required |
variant |
TextLoaderVariant |
required |
color |
CSS color string | "#111111" |
speed |
positive number | 1 |
paused |
boolean |
false |
className |
string |
— |
aria-label |
string |
normalized text |
InlineLoader accepts variant, size, color, speed, paused, className, and an optional accessible label.
ImageLoader accepts variant, size, color, radius, speed, paused, className, and label. Its default label is “Generating image.”
All prop and variant types are exported from the package root.
TextLoaderexposes received text through a polite live status while keeping decorative animation layers hidden from assistive technology.InlineLoaderavoids duplicate announcements when adjacent text already describes the activity; addlabelwhen it stands alone.- Every loader respects
prefers-reduced-motionand retains a meaningful static state. - Text updates are append-aware, so previously received content does not reanimate.
- Components render stable server markup and are safe to use in SSR applications.
- Invalid, zero, or negative speed values safely fall back to
1.
This repository is an npm workspace containing the package and its live gallery.
npm install
npm run devBefore opening a pull request, run:
npm test
npm run lint
npm pack --workspace generative-loaders --dry-runSee CONTRIBUTING.md for the full workflow. For help using the package, read the documentation or open an issue.
MIT © Kasturi Khanke and Generative Loaders contributors.