Spinner
A wait of unknown length, drawn in the text colour at the icon sizes. It announces itself as a status unless it's decorative. Built on the vendored shadcn spinner.
Playground
import { Spinner } from "@/components/shared/spinner";
<Spinner />Sizes
The icon sizes: xs 12px, sm 14px and md 16px match the icons in xs, sm and md/lg buttons; lg 20px is for a wait standing on its own in a panel.
import { Spinner } from "@/components/shared/spinner";
<Spinner size="xs" />
<Spinner size="sm" />
<Spinner />
<Spinner size="lg" />Labels
On its own, a spinner is a status named “Loading”. Pass label to say what's loading, translated. When text beside it already says so, make the spinner decorative and put the status on the text.
Finding free times
import { Spinner } from "@/components/shared/spinner";
<Spinner label={t("loadingSlots")} />
<p role="status" className="flex items-center gap-2 text-sm text-muted-foreground">
<Spinner size="sm" decorative />
Finding free times
</p>In a button
Never place a Spinner inside a Button by hand. Pass loading instead: the button draws a decorative spinner in its leading place at the right size, and sets aria-busy. The spinner takes the colour of the label.
import { Button } from "@/components/shared/button";
<Button loading>Saving</Button>
<Button variant="primary" loading>Creating booking</Button>
<Button variant="secondary" size="sm" loading>Sending code</Button>API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "xs" | "sm" | "md" | "lg" | "md" | 12, 14, 16 or 20px square. |
| label | string | "Loading" | The accessible name, announced as a status. Pass it translated. |
| decorative | boolean | false | Hidden from assistive tech, with no role and no name. Use when visible text or aria-busy already says it's busy. |
| className | string | — | Layout only: margins or placement. The colour comes from the text. |
Everything else passes through to the <svg>.
Guidelines
- Use it for waits of unknown length. When the layout of the answer is known, like a list of slots, hold the space so nothing jumps when it lands.
- Only one thing says “busy”. Either the spinner has a label, or it's decorative beside text or inside a busy control. Never both.
- Keep the label telling: “Loading free times” rather than “Please wait”. In a button, the label says what's happening (“Saving”).
- Never tint it. It follows the text colour, so it stays ink on leaf and white on ink.