# Progress

_Box Kite 2.1.0 · a markdown copy of https://www.box-kite.dev/progress/_

How far a task has got: role=progressbar with the value it really has, an indeterminate bar that reports none at all, and no JavaScript on the server path.

**Import**

```jsx
import Progress from '@box-kite/react/components/progress';
```

**Usage**

```jsx
<Progress label="Upload" value={62} />
```

## No value is a state, not a zero

Leave `value` out and the bar is indeterminate: `aria-valuenow` is left off entirely rather than written as `0`, because the one thing a reader must not be told is a position nobody measured. The bar sweeps instead.

```jsx
<Progress label="Preparing" />
```

The sweep names its duration in milliseconds, so it sits outside the `--transitionTime` that `prefers-reduced-motion` zeroes and stops itself instead — a full-width bar at reduced opacity, which still reads as "working" without anything moving.

## A value that moves

The fill is the one thing here that transitions, and it is the width, so a value arriving in steps still travels between them.

```jsx
<Progress label="Download" value={value} max={100} format={(value) => `${value} per cent`} />
```

## The fill is an inline style, and everything else is a class

A percentage that moves with a download would be a rule per frame if it went into a class name — so the width is an inline `inline-size`, the exception `Slider` explains at length, and the track, the colours, both themes and the forced-colors fallback are shared rules.

Where the value is data rather than an animation, use a ring

`ProgressRing` from `components/chart` rounds its fraction to half a percent and puts it in a class, which costs nothing and shares between every ring on the page. A dashboard of a hundred figures wants that one.

It renders on a server

No state, no effect, no measurement — so a page paints a real figure before any JavaScript arrives, the way `Flex` and `Button` do.

## Its own range

`min` and `max` are what "full" means, so a count of files needs no arithmetic at the call site. `format` writes `aria-valuetext` for a value the bare number does not read as.

```jsx
<Progress label="Files" min={0} max={8} value={3} format={(value) => `${value} of 8 files`} />
```

## Naming it

A progress bar has to be named: a percentage nobody can attach to anything is not information. `label` writes `aria-label` and `labelledBy` points at the heading or the text that already says it.

## Styling

Two parts: `progress`, which is the track and carries the role, and `progress.fill`, whose `indeterminate` variant is the sweep. The root takes Box props directly, so the height and the radius are props on the element.

```jsx
<Progress label="Upload" value={62} height={1} borderRadius={0} />

Box.components({
  progress: { children: { fill: { styles: { bgColor: 'emerald-500' } } } },
});
```

## Progress props

Everything below is this component’s own. All 235 of Box’s style props work on it too, and those are on [/box](https://www.box-kite.dev/box.md) rather than repeated here.

| Prop | Type | Default | What it does |
| --- | --- | --- | --- |
| `value` | `number` | — | How far along it is. Leave it out for a task with no measurable end — the bar sweeps and reports nothing. |
| `min` | `number` | `0` | The bottom of the range. Default `0`. |
| `max` | `number` | `100` | The top of the range, and so what "full" means. Default `100`. |
| `label` | `string` | — | What the bar is called. A progress bar has to be named — nothing about it is readable otherwise. |
| `labelledBy` | `string` | — | The same, naming an element that already says it. |
| `format` | `(value: number) => string` | — | The value as it should be read out: "3 of 10 files", "eleven minutes left". |

## Progress accessibility

- `role="progressbar"` with `aria-valuemin`, `aria-valuemax` and, when there is one, `aria-valuenow`.
- `label` or `labelledBy` is what names it. A bar with neither is a percentage nobody can attach to anything.
- `format` writes `aria-valuetext`, for a value the number alone does not read as.

Swept with axe on every release, in this state: `Progress`. No violations, with contrast and landmark rules left to a human. Screen-reader results are not published yet.

## Progress style tree

Every part the component draws is a node with a name, so a default can be restyled with `Box.components()` instead of a selector — and a variant is a name too.

`progress`

`progress.fill`variants: indeterminate

---

_Every page: https://www.box-kite.dev/llms.txt · every prop, measured: https://www.box-kite.dev/props.md_

