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.
20JSX
<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 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"witharia-valuemin,aria-valuemaxand, when there is one,aria-valuenow.labelorlabelledByis what names it. A bar with neither is a percentage nobody can attach to anything.formatwritesaria-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.progressprogress.fillvariants: indeterminate