# Progress Indicator

`ProgressIndicator` communicates **determinate** progress — a known fraction of
a task that has been completed. Use it when you can express progress as
`value / max`, such as a multi-step setup wizard or a file upload with a known
total size.

For indeterminate activity (loading time or fraction unknown), use
[ActivityIndicator](../ActivityIndicator/ActivityIndicator.md) instead.

Some great use cases for a `ProgressIndicator` include:

* Setup wizards, where we know how many steps the user has completed and how
  many steps remain (use `variation="stepped"`).
* File uploads, where we know the total file size and how much data has already
  been sent (use the default `variation="continuous"`).

## Design & usage guidelines

The default `ProgressIndicator` size is `base` (16px tall) and can be used in
most cases. The `small` (8px) and `smaller` (4px) sizes should be used when the
indicator sits inline with text or in tight surface layouts.

`ProgressIndicator` always fills the width of its parent. Layout — including
inline-vs-block placement — is the consumer's responsibility. Wrap the indicator
with your own flex / `<Stack>` / `<Box>` container, or pass a `className` /
`style`, to control the surrounding layout.

### Continuous vs. stepped

Use `variation="continuous"` (the default) when progress is a smooth value
between `0` and `max` — for example, a file upload where any percentage is
meaningful.

Use `variation="stepped"` when progress is naturally segmented — for example, a
multi-step wizard where the user is on step 2 of 5. Stepped renders `max`
discrete segments and fills the first `value` of them.

## Accessibility

`ProgressIndicator` announces itself politely to assistive technology:

* `role="progressbar"` marks the root element as a progress bar.
* `aria-valuenow`, `aria-valuemin`, and `aria-valuemax` reflect the current
  progress so screen readers can announce the value as a percentage or ratio
  appropriately.
* `aria-label` defaults to a localized-as-English template: `"{value}%"` when
  `max === 100` (or `max` is omitted), and `"{value} / {max}"` otherwise. Pass a
  custom `ariaLabel` to localize or to describe the specific activity (e.g.
  `ariaLabel="Uploading file"`).

In the stepped variation, the individual segments are presentational `<div>`s
with no `role` or `aria-*` attributes. The whole indicator announces once as a
single progressbar — the outer `aria-valuenow` / `aria-valuemax` already carry
the progress information.

The indicator does not participate in the keyboard tab order.

### Reduced motion

The width transition between `value` updates is intentionally **preserved**
under
[`prefers-reduced-motion: reduce`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion).
The slide between progress values conveys functional information about progress,
direction, and magnitude — it is exempt under
[WCAG 2.3.3 ("Animation from Interactions")](https://www.w3.org/WAI/WCAG21/Understanding/animation-from-interactions.html).
Removing the transition would make progress harder to perceive, not easier.

## Relationship to ProgressBar

The legacy [ProgressBar](../ProgressBar/ProgressBar.md) component remains available
and unchanged. New code should prefer `ProgressIndicator`. A follow-up change is
expected to consolidate `ProgressBar` onto `ProgressIndicator`.

`ProgressIndicator` renames `ProgressBar`'s props to align with HTML5
`<progress>` semantics and mobile naming:

| `ProgressBar` (legacy) | `ProgressIndicator` (new) |
| ---------------------- | ------------------------- |
| `currentStep`          | `value`                   |
| `totalSteps`           | `max`                     |
| `variation="progress"` | `variation="continuous"`  |
| `UNSAFE_className`     | `className`               |
| `UNSAFE_style`         | `style`                   |

## Mobile

Mobile (`@jobber/components-native`) has its own `ProgressBar` with a richer
API. The mobile `ProgressIndicator` counterpart is forthcoming as a separate
deliverable.


## Props

### Web

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `value` | `number` | Yes | — | Current progress. Expected to be in the range `0..max` inclusive. |
| `ariaLabel` | `string` | No | — | Accessible label exposed via `aria-label` on the root element. When omitted, defaults to `"{value}%"` when `max === 1... |
| `className` | `string` | No | — | Custom class name merged onto the root element alongside the component's own classes. |
| `max` | `number` | No | `100` | Maximum value. Pass `max={4}` with `value={2}` for "2 of 4 steps"; pass `value={75}` for "75%". |
| `size` | `"base" | "small" | "smaller"` | No | `base` | Visual size. `smaller` renders at 4px tall, `small` at 8px, `base` at 16px. |
| `style` | `CSSProperties` | No | — | Custom inline styles applied to the root element. |
| `variation` | `"continuous" | "stepped"` | No | `continuous` | Visual variation: - `continuous` renders a single fill bar driven by `value / max`. - `stepped` renders `max` segment... |
