Progress
A hand-drawn progress bar with determinate and indeterminate modes.
Overview
A Progress bar communicates how far along a task is. Pass a value for a determinate bar when
you can measure completion; omit it for an indeterminate sweep when you can’t. For very short,
unquantifiable waits prefer a Spinner.
Anatomy
A sketchy rounded rail (comp.progress.bg.rail) with a filled bar (comp.progress.bg.fill) on top,
both outlined with @ghds/sketch-core. The determinate fill width is value / max; the
indeterminate fill is a fixed segment that sweeps across the rail.
Variants & States
| State | Status | Notes |
|---|---|---|
| Determinate | Implemented | Fill width reflects value / max. |
| Indeterminate | Implemented | A segment sweeps across; suppressed under reduced motion. |
| Hover / Focus / Disabled | Not implemented | Progress is not interactive. |
Usage
Do
- Use a determinate bar whenever you can report real progress (bytes uploaded, steps done).
- Give a meaningful label describing the task.
- Set an appropriate max — it defaults to 100 (percent).
Don't
- Don't fake progress with a determinate bar when you don't know the real value — use indeterminate.
- Don't use Progress for indefinite background activity with no end — a Spinner fits better.
Accessibility
- React:
role="progressbar"witharia-valuemin,aria-valuemax, andaria-valuenow(the value attributes are omitted while indeterminate). Pass alabelfor the accessible name. - Web Components:
gh-progresssets the samerole/aria-value*attributes on the host. - React Native: sets
accessibilityRole="progressbar",accessibilityLabel, andaccessibilityValue(note:accessibilityValueis not forwarded to the DOM by react-native-web, soaria-valuenowmay be absent on the web build — the role and label still are). - Reduced motion: the indeterminate sweep is suppressed under
prefers-reduced-motion(web) or the OS “reduce motion” setting (React Native). - See the Accessibility Guide.
Content
No visible text — the label is for assistive tech. Represent the value visually via the fill.
Props API
React@ghds/react
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | Current value. Omit for an indeterminate bar. |
max | number | 100 | Maximum value. |
label | string | — | Accessible label. |
...rest | HTMLAttributes<HTMLDivElement> | — | Native <div> attributes pass through. |
Web Components@ghds/web-components
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | Current value. Omit for an indeterminate bar. |
max | number | 100 | Maximum value. |
label | string | — | Accessible label. |
React Native@ghds/react-native
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | Current value. Omit for an indeterminate bar. |
max | number | 100 | Maximum value. |
label | string | — | Accessible label. |
testID | string | — | Test handle for queries. |
Code examples
// React — @ghds/react
import { Progress } from '@ghds/react/progress';
<Progress value={30} label="30 percent" />; // determinate
<Progress label="Loading" />; // indeterminate (omit value)
<!-- Web Components — @ghds/web-components -->
<script type="module">
import '@ghds/web-components/progress';
</script>
<gh-progress value="30" label="30 percent"></gh-progress>
<gh-progress label="Loading"></gh-progress>
// React Native — @ghds/react-native
import { Progress } from '@ghds/react-native/progress';
<Progress value={60} label="Uploading" />;