Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/spinner.jsonUsage
Import the master file and pass `size` + `variant` (or the `color` alias). `animate-spin` is always on.
TSImport
import { Spinner, type SpinnerVariant, type SpinnerSize } from "@/components/ui/spinner";TSExample
import { Spinner } from "@/components/ui/spinner";
export function Example() {
return <Spinner size="md" variant="brand" />;
}Composition
Anatomy of the Spinner primitive.
Spinner (single component — flat prop API)
├── size="sm | md | lg | xl" (default "md")
├── variant="brand | current | muted | destructive | pixels-1 | pixels-2" (default "brand")
├── color=… (named tint alias OR any CSS color string)
├── icon={LucideIcon} (override the default LoaderIcon)
└── ...props (forwarded to the underlying svg)Default
Plain brand spinner at the default `md` size.
Custom icon
Pass any lucide icon component via the `icon` prop to swap the default `LoaderIcon`.
Size
Four sizes — `sm`, `md`, `lg`, and `xl` — using the brand tint.
Pixels
Two WebGL pixel loaders exposed as Spinner variants: `variant="pixels-1"` (a dithered, lit sphere) and `variant="pixels-2"` (a dithered swirl). Brand-tinted by default; pass any CSS `color` (e.g. `#0ea5e9`) to retint, and `size` to scale.
Button
Drop a Spinner inside a Button using `variant="current"` so it inherits the button label color. Tag with `data-icon="inline-start"` or `"inline-end"` to get the right padding.
Badge
Same pattern inside a Badge — use `variant="current"` and `data-icon` to slot the spinner before or after the label.
SyncingWorking
Empty state
Center a muted `xl` spinner inside a placeholder Card while data is loading.
Item
Drop a Spinner inside a muted `Item` with a `message` title and a trailing `label`. Both are passed as props on the demo.
Processing payment...
$100.00
Item (Plain)
Same Item composition with `background={false}` and no `label` — a plain muted row with just the spinner and message.
Loading...
API Reference
Props exposed by the Spinner and SpinnerItem components.
Spinner
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "xl" | "md" | Icon dimensions — maps to size-3 / size-4 / size-5 / size-6. |
variant | "brand" | "current" | "muted" | "destructive" | "pixels-1" | "pixels-2" | "brand" | Look. Named tints render a spinning icon (`current` inherits the parent's color); `pixels-1` (dither sphere) and `pixels-2` (dither swirl) render WebGL pixel loaders. |
color | SpinnerVariant | (string & {}) | — | A named tint (alias of `variant`) OR any CSS color string (`#0ea5e9`, `rgb(...)`) to tint the whole spinner, pixel variants included. |
icon | LucideIcon | LoaderIcon | Override the default lucide icon (e.g. `LoaderCircleIcon`). |
className | string | — | Override or extend the resolved variant classes. |
SpinnerItem
| Prop | Type | Default | Description |
|---|---|---|---|
message | string | — | Title text shown next to the spinner. |
label | string | — | Optional trailing text (e.g. `$100.00`). When undefined the trailing slot is not rendered. |
background | boolean | true | When `true`, tints the row with the sidebar-hover bg (`#341756/10` light, `white/10` dark). Set to `false` for a plain muted Item with no tint. |
icon | LucideIcon | — | Override the spinner's lucide icon. |
spinnerSize | "sm" | "md" | "lg" | "xl" | — | Forwarded to the inner Spinner's `size` prop. |
spinnerVariant | "brand" | "current" | "muted" | "destructive" | — | Forwarded to the inner Spinner's `variant` prop. |