Spinner

Something is working, and the wait is short.

Syncing 3 projects…

Fig. 1 A spinner inside a saving button and beside a sync status.

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.

Generating response…

Reading 4 files…

Indexing the workspace…
Response generated.

Streaming answers and status lines.

Fig. 2 Two ways to show waiting. Pick by what is on its way.

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:

Terminal

A complete example. Change the values to fit your product:

spinner-example.tsx

The full source is yours to edit once installed:

spinner.tsx