01 · Start here
Quick start
Generative Loaders is a React component library for the waiting states unique to generative products. It requires React 18 or newer and Node 20 or newer.
npm install generative-loadersImport the component and the stylesheet once in your app:
import { TextLoader } from "generative-loaders";
import "generative-loaders/styles.css";
export function Answer({ text }: { text: string }) {
return <TextLoader text={text} variant="decode" />;
}Pass the complete response received so far—not only the newest token. The loader detects the new suffix and animates it while keeping earlier text stable.
02 · Integration
Streaming text
Start with an empty string and append decoded chunks as they arrive. Replace the endpoint with your own streaming route.
"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" />;
}03 · Components
Choose the right primitive
TextLoader
For response text that grows over time. Only the newly received suffix animates.
InlineLoader
For buttons, status rows, and the short wait before any response arrives.
ImageLoader
For a reserved square frame while an image is being generated.
Examples
<TextLoader text={streamedText} variant="decode" color="#7c3aed" />
<span>
<InlineLoader variant="orbit" /> Generating response…
</span>
<ImageLoader
variant="tiles"
size={192}
radius={24}
label="Generating product image"
/>Text variantsdecode · typewriter · skeleton · cascade · focus · wipe · flip · redact · line · terminal · wave · dissolve · slice · tracking · coalesce · fragments
Inline variantsglyph · matrix · orbit · ripple · signal · spark · rotor · pixel-drift · chomp · snake · fold · gravity · domino · aperture · dot-pulse · vortex · halo · count-up
Image variantsskeleton · bands · tiles · scan · pixel-grid · resolution · coalesce · diffusion · raster · bloom · focus · shutter
04 · Reference
Props
TextLoader
textstringrequiredComplete response received so far.variantTextLoaderVariantrequiredVisual reveal treatment.colorCSS color#111111Loader and text color.speedpositive number1Animation speed multiplier.pausedbooleanfalseStops motion without removing content.classNamestring—Custom class on the root element.aria-labelstringnormalized textOverrides announced status text.InlineLoader
Requires variant. Also accepts size (default 1.15em), color (default currentColor), speed, paused, className, and optional label.
ImageLoader
Requires variant. Also accepts size (default 10rem), radius (default 10%), color, speed, paused, className, and label (default “Generating image”). Numeric size and radius values are treated as pixels.
05 · Accessibility
Accessible by default
- TextLoader uses a polite live status and exposes the received text while its visual layers remain hidden from assistive technology.
- InlineLoader is hidden from assistive technology when no label is supplied. This prevents duplicate announcements when adjacent copy already says “Generating”. Add
labelwhen it stands alone. - ImageLoader announces “Generating image” by default. Use a more specific label when the context benefits from it.
- All loaders respect the user’s reduced-motion preference and retain their meaning without animation.
06 · Styling
Styling and behavior
Use props for color, size, radius, and speed. Use className for layout concerns such as margins and alignment. Import the packaged stylesheet exactly once near your application root.
.answer-loader {
display: block;
max-width: 42rem;
font: 500 1.125rem/1.65 system-ui, sans-serif;
}The package is SSR-safe. Components that animate use client-side React behavior, but they render stable markup on the server. TypeScript types for every prop and variant are exported from the package root.
07 · Help
Common pitfalls
The loader is unstyled
Import generative-loaders/styles.css once in your root layout or application entry file.
Every update re-animates the full response
Append chunks to one string. Replacing earlier text or remounting the component with a changing key resets suffix detection.
The inline status is not announced
Add a label when the loader has no adjacent visible status copy. Leave it unset when nearby text already communicates the same activity.
Animation speed behaves unexpectedly
Use a finite positive number. Invalid, zero, and negative values safely fall back to 1.