# Progress

> A thin bar showing how far along something is: a line, segments for steps, or indeterminate.

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

## When to use

- Line: something with a known size that takes a few seconds or more, e.g. an upload or an import.
- Segments: where someone is in a set of steps, e.g. a multi-step form (Slideover's `steps` uses it).
- Indeterminate: something that takes a while with no way to tell how long, e.g. loading a page of results.

## When not to use

- Under a second: show nothing, or a Spinner in the Button that started it.
- Ticking off named tasks: use Checklist.

## Anatomy

| Part | Required | Notes |
|---|---|---|
| track | Yes | 6px tall, fully rounded, black 10%. |
| fill | Yes | Primary, fully rounded. |
| segments | No | One track per step, 4px apart, filled up to the current step. |

## Properties

| Property | Type | Default | Description |
|---|---|---|---|
| value | number \| null | null | Done so far. Null or left out: indeterminate. |
| max | number | 100 | The total; with `segments`, the number of segments. |
| segments | boolean | false | Split into `max` segments and fill `value` of them. |
| label | string | — | Required. Accessible name, e.g. "Uploading report.pdf". Not shown. |

## Behaviour

- Line and segments ease to a new value over 300ms. Values outside 0–`max` are clamped.
- Indeterminate: a bar 40% wide sweeps from left to right every 1.5s.
- Reduced motion: no easing; indeterminate becomes a full bar that gently pulses.

## Accessibility

- `role="progressbar"` named by `label`, with `aria-valuenow` / `aria-valuemax`.
- Value text: "40%" for a line, "Step 2 of 4" for segments. Indeterminate has no value and is `aria-busy`.

## Platform adaptation

| Platform | Implementation | Differences |
|---|---|---|
| Web / desktop (Vue) | `Progress.vue` | Reka UI Progress. |
| iOS (SwiftUI) | — | `ProgressView(value:total:)` with a custom style; indeterminate as the same sweeping bar. |
| Android (Compose) | — | `LinearProgressIndicator`, determinate or not; segments as a Row of them. |

## Tokens used

| Token | Used for |
|---|---|
| `color-primary` | Fill |
| `animate-progress-indeterminate` | Indeterminate sweep |

## API (from the source)

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

```ts
// Progress.vue
/**
 * How far along something is, as a thin bar. Three forms:
 * - a line that fills up, e.g. an upload (`value` out of `max`);
 * - segments, one per step, e.g. a multi-step form (`segments`, with `value`
 *   steps filled out of `max`);
 * - indeterminate, when there's no telling how long it'll take (no `value`).
 * Built on Reka UI's Progress, so it's announced as a progress bar.
 */
export interface ProgressProps {
  /** Done so far, out of `max`. Leave it out (or null) for indeterminate. */
  value?: number | null
  /** The total. With `segments`, the number of segments. */
  max?: number
  /** Split the bar into `max` segments and fill `value` of them. */
  segments?: boolean
  /** What's progressing, e.g. "Uploading report.pdf". Its accessible name; not shown. */
  label: string
  class?: HTMLAttributes['class']
}
```
