# Spinner

> A small circular loading indicator: spinning while there's no telling how long, or a ring that fills up.

- Import: `import { Spinner } from '@thekestongroup/ui'`
- Group: Element
- Live example: https://ui.keston.co/storybook/?path=/story/components-element-spinner--continuous
- Source: https://github.com/thekestongroup/ui/blob/main/src/components/Spinner/Spinner.vue

## When to use

- Short waits in a small space: inside a Button while saving, next to a field's "Checking…" message, in a card while it loads.
- `lg` with a value: progress you want people to watch, e.g. an upload in an empty state.

## When not to use

- Progress across the width of a page or panel, or steps: use Progress.
- Waits under about a second: show nothing.

## Anatomy

| Part | Required | Notes |
|---|---|---|
| track | Yes | The full ring, in the current text colour at 20% opacity. |
| arc | Yes | Spins, or fills to the value. Current text colour. |
| percentage | No | In the middle, `lg` only, with a value. |

## Properties

| Property | Type | Default | Description |
|---|---|---|---|
| value | number \| null | — | Progress from 0 to `max`. Leave out for a continuous spinner. |
| max | number | 100 | The value that means complete. |
| size | sm \| md \| lg | md | 16px (a button icon) · 24px · 48px. |
| label | string | Loading | What's loading, for screen readers, e.g. "Uploading report". |
| showValue | boolean | false | Show the percentage in the middle (`lg` with a value only). |

## Behaviour

- Takes the surrounding text colour, like an icon: colour it with a text class on it or its parent, e.g. `text-primary`.
- Continuous: spins once a second; with reduced motion it turns slowly, once every two seconds.

## Accessibility

- `role="progressbar"`, named by `label`, with the value when there is one.

## Platform adaptation

| Platform | Implementation | Differences |
|---|---|---|
| Web / desktop (Vue) | `Spinner.vue` | SVG. |
| iOS (SwiftUI) | — | `ProgressView()` (circular), or with a value. |
| Android (Compose) | — | `CircularProgressIndicator`. |

## Tokens used

| Token | Used for |
|---|---|
| currentColor | Track and arc |

## API (from the source)

The component's exact props, model, events, slots and types, with their documentation comments.

```ts
// Spinner.vue
/**
 * A circular progress indicator.
 *
 * - No `value` (or `null`): continuous spinner, for waits of unknown length.
 * - `value` from 0 to `max`: a ring that fills as the value goes up.
 *
 * It takes the surrounding text colour, like an icon, so put a text colour
 * class on it or its parent (e.g. `class="text-primary"`).
 */
export interface SpinnerProps {
  /** Progress from 0 to `max`. Leave out (or null) for a continuous spinner. */
  value?: number | null
  /** The value that means complete. */
  max?: number
  /** sm 16px (button icon size) · md 24px · lg 48px */
  size?: 'sm' | 'md' | 'lg'
  /** What is loading, read by screen readers, e.g. "Uploading report". */
  label?: string
  /** Show the percentage in the middle. Only on `lg`, and only with a value. */
  showValue?: boolean
  class?: HTMLAttributes['class']
}
```
