01 / 37 · Reasoning
Loading state
A pixel matrix that keeps time while the model has nothing to show yet.
Generating
Installation
npx shadcn@latest add "@assistant-ui/elements-loading-state"
Usage
import { GenerationLoader } from "@/components/elements/loading-state";
<GenerationLoader label="Generating" tick={24} />Props
label*stringStatus copy shown under the pixel grid while the model has nothing else to show.
tick*numberAnimation clock that advances the pixel pattern and the elapsed seconds counter.
variant"dots" | "squares" | "rounded"Cell shape of the pixel matrix.
classNamestringExtra classes merged onto the root.
Source
loading-state.tsx"use client";
import { cn } from "@/lib/utils";
export type GenerationLoaderVariant = "dots" | "squares" | "rounded";
export interface GenerationLoaderProps {
label: string;
tick: number;
variant?: GenerationLoaderVariant;
className?: string;
}
const CELL_SHAPES: Record<GenerationLoaderVariant, string> = {
dots: "rounded-full",
squares: "rounded-[1px]",
rounded: "rounded-[3px]",
};
export function GenerationLoader({
label,
tick,
variant = "dots",
className,
}: GenerationLoaderProps) {
const pixelOffset = Math.floor(tick / 3);
return (
<div className={cn("flex flex-col items-center gap-4", className)}>
<div aria-hidden className="grid grid-cols-3 gap-1">
{Array.from({ length: 9 }, (_, index) => {
const active = (index * 2 + pixelOffset) % 9 < 3;
return (
<span
key={index}
className={cn(
"bg-foreground size-2 transition-opacity duration-300 motion-reduce:transition-none",
CELL_SHAPES[variant],
active ? "opacity-90" : "opacity-15",
)}
/>
);
})}
</div>
<span className="text-foreground/55 relative inline-block text-sm">
<span>{label}</span>
<span
aria-hidden
className="shimmer pointer-events-none absolute inset-0 motion-reduce:animate-none"
>
{label}
</span>
</span>
</div>
);
}