Components
An indicator that can be used to show a loading state.
Playground
SpinnerIcon with role="status" and aria-label="Loading", spinning at 1s per turn — a 16px icon that inherits the text color wherever it lands.import { Spinner } from "@workspace/ui/components/spinner"
<Spinner />size-4 (16px). Override it with a size-* utility — classes merge through cn(), so yours wins over the base one.<Spinner className="size-3" /> <Spinner className="size-4" /> <Spinner className="size-6" /> <Spinner className="size-8" />
currentColor — there is no color prop or token of its own. Set a text-* class on the spinner or on a parent and it follows.<Spinner className="size-6 text-primary" /> <Spinner className="size-6 text-muted-foreground" /> <Spinner className="size-6 text-destructive" />
data-icon="inline-start" so the button tightens its start padding, and disable the button while the action is pending.<Button disabled size="sm"> <Spinner data-icon="inline-start" /> Loading... </Button> <Button variant="outline" disabled size="sm"> <Spinner data-icon="inline-start" /> Please wait </Button> <Button variant="secondary" disabled size="sm"> <Spinner data-icon="inline-start" /> Processing </Button>
data-icon="inline-start" attribute tightens the badge's start padding.<Badge> <Spinner data-icon="inline-start" /> Syncing </Badge> <Badge variant="secondary"> <Spinner data-icon="inline-start" /> Updating </Badge> <Badge variant="outline"> <Spinner data-icon="inline-start" /> Processing </Badge>
align="inline-end" for a compact input, or align="block-end" with a status label under a textarea.<InputGroup>
<InputGroupInput placeholder="Send a message..." disabled />
<InputGroupAddon align="inline-end">
<Spinner />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupTextarea placeholder="Send a message..." disabled />
<InputGroupAddon align="block-end">
<Spinner /> Validating...
<InputGroupButton className="ms-auto" variant="default">
<ArrowUpIcon />
<span className="sr-only">Send</span>
</InputGroupButton>
</InputGroupAddon>
</InputGroup><Empty className="w-full">
<EmptyHeader>
<EmptyMedia variant="icon">
<Spinner />
</EmptyMedia>
<EmptyTitle>Processing your request</EmptyTitle>
<EmptyDescription>
Please wait while we process your request. Do not refresh the page.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button variant="outline" size="sm">
Cancel
</Button>
</EmptyContent>
</Empty>className, or target data-slot="spinner" from a parent. Override aria-label to localize the announced text.| Component | Prop | Default |
|---|---|---|
| Spinner | className?: string | — |
| Spinner | aria-label?: string | "Loading" |
<Spinner data-slot="spinner" role="status" />
Tokens used
2 design tokens consumed by the Spinner component.
--spacing
Spacing unit (4px)
--animate-spin
Spin (1s linear infinite)