Spinner
Something is working, and the wait is short.
Syncing 3 projects…
When to use it
Use Spinner for waits of a second or two, inside the button or panel that’s busy. Keep the surrounding layout still.
For text that arrives piece by piece, use Shimmer. For longer waits, show progress or what’s happening.
SpinnerThis page
Working on it.
Syncing 3 projects…
Buttons and panels waiting briefly.
Shimmer
Text on its way.
Reading 4 files…
Streaming answers and status lines.
How it behaves
Spinner renders the Loader2Icon from lib/icons with role="status" and an accessible name of Loading. Pass aria-label to describe the work, such as Searching.
Inside a control or beside text that already says what is happening, pass aria-hidden="true" so the status isn't announced twice.
It inherits the current text color and is 16px by default; set a size class to change it. In a Button, mark it data-icon="start" for the icon inset and set aria-busy while pending. Pair disabled with focusableWhenDisabled so the button blocks repeat presses but keeps focus and full strength, reading as working rather than unavailable.
A filled Button may show a spinner only as transient state: resolve it to a result such as Saved, then return to the label. Reduced motion slows the rotation instead of stopping it.
Build it
Add it with the shadcn CLI:
1pnpm dlx shadcn@latest add https://jzbui.com/r/spinner.jsonA complete example. Change the values to fit your product:
12345678910import { Spinner } from "@/components/ui/spinner"import { Button } from "@/components/ui/button"
<Spinner /><Spinner aria-label="Searching" />
<Button disabled focusableWhenDisabled aria-busy> <Spinner aria-hidden="true" data-icon="start" /> Saving…</Button>The full source is yours to edit once installed: