# Spinner

> A React loading spinner for waits without a known shape: six styles, from a quiet ring to the iOS spokes, in any size, tone or speed.

- Type: React component (Feedback)
- Access: Free (the source is open to everyone)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add spinner`
- Docs: https://wingo-ui.com/components/spinner

## Interaction

It turns on its own and never takes focus. Screen readers hear its label once, as a polite status, and nothing else; inside a parent that already announces the wait (a loading button) pass aria-hidden and it stays silent. With a delay it stays invisible for fast loads and fades in only when the wait gets long enough to notice. Under reduced motion it keeps turning at half speed, so the page still reads as busy. Every style animates only transform and opacity on the compositor, so it keeps moving while the page is busy.

## Installation

```bash
npx wingo-ui@latest add spinner
```

The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add https://wingo-ui.com/r/spinner.json`

Files:

- `components/ui/spinner.tsx`

Wingo UI dependencies (installed automatically):

- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))

## Usage

```tsx
import { Spinner } from "@/components/ui/spinner"

export function ListingsLoading() {
  return (
    <div className="flex flex-col items-center gap-3 py-12 text-muted-foreground">
      <Spinner variant="spokes" size="lg" delay={300} label="Loading listings" />
      <p className="text-sm">Searching apartments in New York…</p>
    </div>
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant?` | `"ring" \| "dots" \| "bars" \| "pulse" \| "orbit" \| "spokes"` | `"ring"` | ring: a quarter arc over a faint track. dots: three dots in a wave. bars: three bars like an equalizer. pulse: a dot with an expanding ring. orbit: two dots circling. spokes: the iOS activity indicator, 8 spokes (12 from 40px) with the light traveling clockwise. |
| `size?` | `"sm" \| "md" \| "lg" \| number` | `"md"` | 16 / 24 / 40px, or any px number (12 at least). sm for inline text and buttons, md for cards and panels, lg for a whole page. The ring stroke and the label grow with it. |
| `tone?` | `"current" \| "neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"current"` | current follows the text color, so it works inside any colored parent (a solid button, a colored chip). A tone paints the indicator with the design tokens and the visible label with the readable tone text. |
| `color?` | `string` | `""` | Any CSS color. Replaces the tone; faded parts use the same color at lower opacity. Leave empty to use the tone. |
| `speed?` | `number` | `1` | Playback multiplier: 0.5 is half speed, 2 twice as fast. Clamped to 0.25 to 4. Every style keeps its own rhythm (ring 0.75s, spokes 0.8s, dots 1s per loop). |
| `label?` | `string` | `"Loading"` | The accessible name, announced once as a polite status. Shown next to the indicator with showLabel. Pass aria-hidden when a parent already announces the loading (a loading button): the spinner then drops its status role and this label. |
| `showLabel?` | `boolean` | `false` | Shows the label next to (or under) the indicator. Without it the label is only for screen readers. |
| `labelPosition?` | `"end" \| "bottom"` | `"end"` | end sits beside the indicator for inline use; bottom stacks it, for page and panel loaders. |
| `track?` | `boolean` | `true` | Ring only: the faint full circle under the arc. Turn it off for a lighter look on busy backgrounds. |
| `delay?` | `number` | `0` | Milliseconds before anything renders, label included, counted from mount. 300 hides the spinner entirely for fast loads, so it never flashes; after the wait it fades in. A spinner that is already showing never hides again when delay changes (remount it with a key to replay the wait). |
| `paused?` | `boolean` | `false` | Holds the current frame. Useful while a pull-to-refresh is still being dragged, or for a still in a gallery. |
| `classNames?` | `Partial<Record<"indicator" \| "label", string>>` |  | Extra classes for the drawing (svg or span) and the label. |
| `className?` | `string` |  | Extra classes for the root span, merged last. Override the color with [--spinner-color:...]. |
| `style?` | `CSSProperties` |  | Inline styles for the root span. |

## Examples

- **Six styles**: ring, dots, bars, pulse, orbit and spokes at the default md size.
- **Sizes**: sm 16, md 24, lg 40 or any px number. Spokes switch to 12 from 40px.
- **Tones and custom color**: Six tones, a custom violet, and current color inside a brand chip and a loading button.
- **Inline and in rows**: An sm autosave spinner with its label beside a title, and one trailing a list row in the muted text color.
- **Delay**: Both use delay={300}. The 200 ms request finishes before the spinner would show, so it never flashes.
- **Page loader**: lg spokes with the label stacked under it, for a whole screen that is waiting.
- **Pull to refresh**: Drag the list down: the paused spokes wind up with your finger and start spinning when you let go.
- **Speed**: A multiplier on each style's own rhythm: 0.5, 1 and 2.

## See also

- [Skeleton](https://wingo-ui.com/components/skeleton) ([Markdown](https://wingo-ui.com/components/skeleton.md))
- [Progress](https://wingo-ui.com/components/progress) ([Markdown](https://wingo-ui.com/components/progress.md))
- [Route Progress](https://wingo-ui.com/components/route-progress) ([Markdown](https://wingo-ui.com/components/route-progress.md))
- [Pull To Refresh](https://wingo-ui.com/components/pull-to-refresh) ([Markdown](https://wingo-ui.com/components/pull-to-refresh.md))
- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))

---

Canonical: https://wingo-ui.com/components/spinner
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
