Progress
Progress shows how far a task has advanced as a horizontal bar ('linear') or
a ring ('circular'). The anatomy is the same for both appearances: the root is
the wrapper and accessibility owner, Progress.Track is the rail (the linear
rail bar, or the ring svg drawing the rail circle), Progress.Indicator is the
filled portion, and Progress.Value composes decorative value or status text —
in flow next to the linear track, centered inside the circular ring.
Set indeterminate while the work's extent is unknown — the indicator loops a
sweep animation instead of a fill. For standalone loading states with no
progress semantics, a Spinner is still the right
component.
The root carries role="progressbar" with the full aria-valuemin /
aria-valuemax / aria-valuenow surface, so assistive technology announces the
value without extra wiring. Compose it inside a
Field with Field.Label for a
visible label — the accessible name and the field's disabled state wire up
automatically.
Usage
import { Field, Progress } from '@takeoff-ui/react-spar';
<Progress value={33} />
<Field>
<Field.Label>Upload progress</Field.Label>
<Progress size="large" value={66} />
</Field>
<Progress value={40}>
<Progress.Track />
<Progress.Value>%40</Progress.Value>
</Progress>
<Progress appearance="circular" value={66} aria-label="Upload progress">
<Progress.Track />
<Progress.Value>%66</Progress.Value>
</Progress>
Playground
Variants
variant recolors the filled portion of the track.
Circular
appearance="circular" renders Progress.Track as the ring svg — it draws the
rail circle and hosts the arc indicator. Progress.Value composes value or
status text centered inside the ring — it is decorative (aria-hidden), so keep
the accessible name on the root via aria-label or a Field.Label.
Sizes
size scales the linear track height and the composed linear Progress.Value
typography, plus the circular ring diameter. Circular sizes are 64px, 96px,
and 128px for small, base, and large — the centered Progress.Value
typography scales with the ring automatically.
Indeterminate
Set indeterminate when the work's extent is unknown — the indicator loops a
sweep animation, the root drops aria-valuenow, and data-indeterminate is
emitted for styling hooks. It takes precedence over value.
Disabled
disabled mutes the fill and sets aria-disabled. Inside a disabled Field
the state is inherited, so the label and the filled portion gray out together.
Block / Inline
Linear progress can be composed as a block pattern with the percentage below the
bar, or as an inline pattern with the percentage beside the bar. The linear root
stacks Progress.Track and Progress.Value with the design's sign gap; for the
inline pattern flip the root to a row layout with an inline style (the
recipe's layout styles take precedence over utility classes).
Sections
Progress.Track accepts custom children, so a stacked breakdown composes as
plain segments inside the rail — the track's radius and overflow: hidden clip
them into the bar shape. Give the track a taller inline height to fit
per-segment value text (the design rail is 4–8px). Keep the aggregate on the
root's value and pass aria-valuetext so assistive technology announces the
total meaningfully; the in-segment texts stay aria-hidden.
Accessibility
- The root exposes
role="progressbar"witharia-valuemin,aria-valuemax, and the clampedaria-valuenow. When indeterminate,aria-valuenowis omitted so assistive technology announces a busy progressbar instead of a bogus percentage. - Composing inside a
FieldwithField.Labelwiresaria-labelledbyto the label automatically. Outside aField, passaria-labeloraria-labelledby; without either, the root falls back to a defaultaria-label. - Pass
aria-valuetextwhen the raw number reads poorly — e.g.aria-valuetext="3 of 10 steps"— and assistive technology announces the formatted text instead of the percentage. - The rendered track, indicator, and
Progress.Valueare decorative and hidden from assistive technology — the value is announced througharia-valuenow. - Motion respects
prefers-reduced-motion: the determinate fill transition is dropped entirely, and the indeterminate sweep slows down (it still conveys "working", the same policy asSpinner).
API Reference
Progress
Props
| Name | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | - | Optional anatomy override. When omitted, the root renders the default anatomy — Progress.Track wrapping Progress.Indicator — for both appearances. |
| value | number | 0 | Current progress value. Clamped to [min, max]; non-finite values resolve to min. Ignored while indeterminate is set. |
| indeterminate | boolean | false | Marks the progress as indeterminate — the root drops aria-valuenow, emits data-indeterminate, and the indicator animates a looping sweep instead of a fill. Takes precedence over value. |
| min | number | 0 | Minimum value the progress starts from. Non-finite values fall back to the default. |
| max | number | 100 | Maximum value the progress can reach. Non-finite values and values at or below min fall back to min + 100 (the latter with a dev-only console warning, since an inverted range is a consumer bug). |
| appearance | ProgressAppearance | 'linear' | Shape of the progress indicator — a horizontal bar ('linear') or a ring ('circular'). |
| size | ProgressSize | 'base' | Visual scale. Linear progress changes track height; circular progress changes ring diameter. |
| variant | ProgressVariant | 'primary' | Fill color variant. |
| disabled | boolean | false | Mutes the fill color and sets aria-disabled. Inherits the surrounding Field's disabled state when composed inside one. |
| classNames | Partial<Record<"root", string>> | - | Per-slot class name overrides. |
| slotProps | Partial<Record<"root", HTMLAttributes<HTMLElement>>> | - | Per-slot HTML attribute overrides. |
| className | string | - | Appends custom classes to the root slot of this part. |
Data attributes
| Attribute | Applied when | Purpose |
|---|---|---|
| data-slot="root" | Always | Stable selector for wrapper styling on the root slot. |
| data-type | Always | Reflects the resolved appearance prop (linear | circular). |
| data-size | Always | Reflects the resolved size prop so recipes can scale the bar or ring. |
| data-variant | Always | Reflects the resolved variant prop so theme recipes can recolor the fill. |
| data-disabled | disabled (own prop or inherited from a surrounding Field) | Mutes the fill color through the recipe. |
| data-indeterminate | indeterminate | Marks the indeterminate state; aria-valuenow is dropped alongside it. |
| data-complete | Determinate and the clamped value reaches max | Styling hook for finished states (e.g. a success fill at 100%). It flips the instant the value reaches max — the fill’s 0.3s transition may still be catching up visually, so completion styling leads the fill slightly. |
Progress.Track
Data attributes
| Attribute | Applied when | Purpose |
|---|---|---|
| data-slot="root" | Always | Stable selector for wrapper styling on the root slot. |
| data-slot="rail" | appearance="circular" | The rail <circle> the ring svg draws; style or override it via classNames.rail / slotProps.rail. |
| data-type | Always | Reflects the root’s resolved appearance so the part’s recipe styles itself without root selectors. |
Progress.Indicator
Data attributes
| Attribute | Applied when | Purpose |
|---|---|---|
| data-slot="root" | Always | Stable selector for wrapper styling on the root slot. |
| data-type | Always | Reflects the root’s resolved appearance so the part’s recipe styles itself without root selectors. |
| data-indeterminate | indeterminate | Drives the looping sweep animation instead of a written fill. |
Progress.Value
Data attributes
| Attribute | Applied when | Purpose |
|---|---|---|
| data-slot="root" | Always | Stable selector for wrapper styling on the root slot. |
| data-type | Always | Reflects the root’s resolved appearance so the part’s recipe styles itself without root selectors. |
Type Definitions
| Name | Definition |
|---|---|
| ProgressAppearance | 'linear' | 'circular' |
| ProgressSize | 'small' | 'base' | 'large' |
| ProgressVariant | 'primary' | 'info' | 'success' | 'danger' | 'warning' |
| ProgressTrackSlot | 'root' | 'rail' |