Spinner
Animated circular loading indicator. Displays loading state with accessibility support and multiple size options.
AccessibleDark Mode3 Sizes2 VariantsAnimated
Install
$
npx react-principles add spinner01
Live Demo
Explore all variants and interactive states in Storybook.
Open Storybookopen_in_newSizes
Loading...
SmallLoading...
MediumLoading...
LargeVariants
Loading...
Default (primary color)Loading...
Muted (subtle)With Text
Loading...
Loading data...Loading...
Saving changes...Loading...
Processing file...On Colored Backgrounds
Loading...
Primary backgroundLoading...
Dark background02
Code Snippet
src/ui/Spinner.tsx
import { Spinner } from "@/ui/Spinner"; // Basic usage <Spinner /> // Sizes <Spinner size="sm" /> <Spinner size="md" /> <Spinner size="lg" /> // Variants <Spinner variant="default" /> <Spinner variant="muted" /> // With custom label <Spinner label="Loading data..." />
03
Copy-Paste (Single File)
Spinner.tsx
import { cn } from "@/lib/utils"; // ─── Types ──────────────────────────────────────────────────────────────────── export type SpinnerSize = "sm" | "md" | "lg"; export type SpinnerVariant = "default" | "muted"; export interface SpinnerProps { size?: SpinnerSize; variant?: SpinnerVariant; label?: string; } // ─── Constants ──────────────────────────────────────────────────────────────── const SIZE_CLASSES: Record<SpinnerSize, string> = { sm: "w-4 h-4", md: "w-5 h-5", lg: "w-6 h-6", }; const VARIANT_CLASSES: Record<SpinnerVariant, string> = { default: "text-primary", muted: "text-slate-400 dark:text-slate-600", }; // ─── Component ──────────────────────────────────────────────────────────────── export function Spinner({ size = "md", variant = "default", label }: SpinnerProps) { return ( <div role="status" aria-live="polite" className="inline-flex"> <svg aria-hidden="true" className={cn("animate-spin", SIZE_CLASSES[size], VARIANT_CLASSES[variant])} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" > <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /> <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" /> </svg> <span className="sr-only">{label || "Loading..."}</span> </div> ); }
04
Props
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | Size of the spinner. sm is 16px, md is 20px, lg is 24px. |
variant | "default" | "muted" | "default" | Visual style. default uses primary color, muted is subtle for colored backgrounds. |
label | string | "Loading..." | Accessible label for screen readers. Override to provide context-specific message. |