---
title: Spinner
description: An indicator that can be used to show a loading state.
icon: loader
author:
  name: shadcn
  url: https://github.com/shadcn
search:
  keywords: [loader, loading indicator]
related:
  - /skeleton
  - /progress
mode: wide
---

<PoweredBy packages={[{ name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/spinner' }]} />

### Installation

```package-install
npx shadcn@latest add @redpanda/spinner
```

<ComponentPreview name="spinner-demo" />

## When to use

Use this decision tree to determine when to use the Spinner component:

```mermaid
graph TD;
    A[❓ Need loading indicator?] -->|Yes| B{User action pending?};
    A -->|No| C[ℹ️ Use progress bar];
    B -->|Yes| D{Button action?};
    B -->|Yes| E{Form submission?};
    D -->|Yes| F[✅ Add Spinner to Button];
    E -->|Yes| G[✅ Show Spinner near form];
    B -->|Yes| H{Page/section loading?};
    H -->|Yes| I[✅ Use Spinner in Empty state];
    B -->|Yes| J{Input processing?};
    J -->|Yes| K[✅ Add Spinner in InputGroupAddon];
    B -->|Yes| L{List item loading?};
    L -->|Yes| M[✅ Use Spinner in ItemMedia];

    classDef recommended fill:#4ade80,stroke:#22c55e,stroke-width:2px,color:#000;
    classDef discouraged fill:#fbbf24,stroke:#f59e0b,stroke-width:2px,color:#000;
    classDef decision fill:#60a5fa,stroke:#3b82f6,stroke-width:2px,color:#fff;
    classDef neutral fill:#9ca3af,stroke:#6b7280,stroke-width:2px,color:#fff;

    class F,G,I,K,M recommended;
    class A,B,D,E,H,J,L decision;
    class C neutral;
```

## Usage

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

```tsx
<Spinner />
```

## Anatomy

The Spinner component is a simple animated loading indicator. Here's how it's structured:

```tsx
<Spinner />  {/* Animated icon with spin animation */}
```

### Layout Structure

- **Spinner**: Single SVG icon with `animate-spin` animation applied
- Size controlled via className (`size-4`, `size-6`, etc.)
- Color controlled by the finite `tone` recipe; the default inherits its surrounding control's ink

### Typical Usage Patterns

```tsx expandable
// Standalone
<Spinner />

// Custom size
<Spinner className="size-8" />

// Owned context color
<Spinner tone="primary" />

// In button
<Button disabled>
  <Spinner />
  Loading...
</Button>

// In badge
<Badge>
  <Spinner className="size-3" />
  Processing
</Badge>

// In input group
<InputGroup>
  <InputGroupInput placeholder="Searching..." />
  <InputGroupAddon>
    <Spinner />
  </InputGroupAddon>
</InputGroup>

// In empty state
<Empty>
  <EmptyHeader>
    <EmptyMedia>
      <Spinner className="size-8" />
    </EmptyMedia>
    <EmptyTitle>Loading data</EmptyTitle>
  </EmptyHeader>
</Empty>

// In item
<Item>
  <ItemMedia>
    <Spinner />
  </ItemMedia>
  <ItemContent>
    <ItemTitle>Processing...</ItemTitle>
  </ItemContent>
</Item>
```

## Customization

Use the installed component's `tone` recipe rather than copying a second spinner implementation or overriding its
text color. If you change the glyph in the installed owner, preserve the finite tones, native SVG props, and
`role="status"` accessibility contract.

## Examples

### Size

Use the `size-*` utility class to change the size of the spinner.

<ComponentPreview name="spinner-size-demo" />

### Color

Use `tone` for a supported context color. It does not change the pending state into a completed or failed operation.
The default inherits the current color so spinners inside buttons and badges keep the correct foreground in both themes.

<ComponentPreview name="spinner-color-demo" />

### Button

Add a spinner to a button to indicate a loading state. The `<Button />` will handle the spacing between the spinner and the text.

<ComponentPreview name="spinner-button-demo" />

### Badge

You can also use a spinner inside a badge.

<ComponentPreview name="spinner-badge-demo" />

### Input Group

Input Group can have spinners inside `<InputGroupAddon>`.

<ComponentPreview name="spinner-input-group-demo" />

### Empty

<ComponentPreview name="spinner-empty-demo" />

### Item

Use the spinner inside `<ItemMedia>` to illustrate a loading state. This example is a static download snapshot,
not a live transfer. Its progress matches the displayed 129 MB out of 1000 MB; it has no pretend Cancel action.

<ComponentPreview name="spinner-item-demo" />

## API Reference

### Spinner

Use the `Spinner` component to display a spinner.

| Prop | Type | Default | Description |
| - | - | - | - |
| `tone?` | `'default' \| 'primary' \| 'brand' \| 'informative' \| 'success' \| 'warning' \| 'destructive'` | `default` | Owned context ink; default inherits the surrounding control without claiming task completion |
| `className?` | `string` | - | Geometry and layout classes, not text-color overrides |

```tsx
<Spinner />
```

## Props

<div className="flex flex-row gap-x-3">
  <ExternalLink href="https://ui.shadcn.com/docs/components/spinner" text="Docs" />
</div>

## Credits

- We take our inspiration from [Shadcn UI](https://ui.shadcn.com/docs/components/spinner) for the `spinner` component and style.
