Progress Bar
Linear track that shows how far a determinate operation has progressed (download %, multi-step form completion, quota usage), or a sweeping animation for indeterminate work. Mirrors Figma node 3007-14257 (light) + 5917-1593 (dark) 1:1. Two sizes (8 px / 12 px), seven colours (Brand / Blue / Green / Purple / Orange / Yellow / Red), and an indeterminate variant. The track is full-width by default; clip it with a wrapper width when you need a fixed length.
When to use
- Use for operations with a known duration (file upload, form completion percentage)
- Use Indeterminate variant when the duration is unknown (loading, processing)
- Show a percentage or step label alongside the bar for clarity
- Use semantic colours consistently — Green for completion, Blue for progress, Red for errors
- Use for ratings — use the Rating component instead
- Use for step-by-step wizards without step labels — use a Step indicator
- Set a fixed width — Progress Bar is full-width by default; clip with a wrapper
- Use more than one progress bar for the same operation
DigiLawyer Patterns
No specific DigiLawyer patterns documented yet — to be added.
Anatomy
A Progress Bar is a track with a fill element. Width is driven by a --pct CSS custom property set inline.
- 1Track —
.progress. Full-width pill-shaped container. Add colour modifier. - 2Fill —
.progress-fill. Width =var(--pct)set as inline style on the track. - 3Colour modifier —
.progress-brand/.progress-infoetc. Seven semantic colours. - 4Indeterminate —
.progress-indeterminate. CSS animation sweeps the fill back and forth. No--pctneeded.
Default
A .progress track with a single .progress-fill child. The fill width is driven inline via style="width: N%;" (or via JS for live updates). Add role="progressbar" plus aria-valuemin / aria-valuemax / aria-valuenow for screen-reader users. Default colour is Brand, default size is Small (8 px).
Variants
Seven colour modifiers — apply .progress-{color} alongside the base .progress. Each variant swaps three tokens: the track background (~20% alpha of the progress colour), an always-transparent border (kept named so an outlined variant can swap it without forking the CSS), and the solid progress fill. Brand is the only outlier — its track uses neutral black @ 10% (white @ 10% in dark) instead of a tinted background, so it reads as a primary system colour rather than a coloured semantic.
Sizes
Two heights pulled directly from Figma. Small (.progress-sm, 8 px) is the default — quietest, best for dense surfaces (cards, list rows, multi-bar dashboards). Medium (.progress-md, 12 px) reads at a longer glance distance — use it for the primary action on a page (upload, multi-step wizard, quota). Both clip the fill via overflow: hidden + border-radius: var(--radius-full) so the fill pill stays inside the track at every value, including 0% and 100%.
States
Progress Bar is a value-driven primitive — there is no hover, focus, or disabled state. The states that matter are value (0% / 50% / 100%) and indeterminate (when duration is unknown — file upload before headers, server-side processing). Indeterminate is a class modifier (.progress-indeterminate) that ignores aria-valuenow and runs a 1.4 s sweep across the track. Use it sparingly — switch back to determinate as soon as you can compute a percentage. The live demo below ramps a real percentage so you can see the width transition.
Interactive
Live demo. The Value row sets a determinate percentage (jump to 0/25/50/75/100), ramps from the current value to 100, or flips into indeterminate. The Colour and Size rows behave like radio groups — only one option active at a time, selection swaps a modifier class on the live bar. Active selection is shown with the dark primary fill so the current state is unmistakable. Width transitions use a 0.24 s ease (see .progress-fill in components.css).
Full matrix
Size × colour at five representative values. Determinate only — indeterminate has no value axis so it lives in States. This is the canonical reference grid for cross-mode comparison; toggle the theme switch in the global header to see every cell under dark tokens.
Accessibility
| Attribute / Behaviour | Value | Notes |
|---|---|---|
| Role | role="progressbar" | Set on the .progress track element |
| Current value | aria-valuenow="65" | Update dynamically as the value changes |
| Range | aria-valuemin="0" + aria-valuemax="100" | Set the scale context for screen readers |
| Label | aria-label="Upload progress" | Describe what is progressing — the bar alone has no context |
| Indeterminate | Omit aria-valuenow | When duration is unknown, remove aria-valuenow so screen readers announce it as indeterminate |
| Completion | Announce via live region | When progress reaches 100%, announce "Complete" via aria-live="polite" |
API
| Class / attr | On | Description |
|---|---|---|
| .progress | <div role="progressbar"> | Track wrapper. Full-width by default — clip with a parent or inline width. 8 px tall, pill-shaped (--radius-full), overflow: hidden so the fill clips at the corners. |
| .progress-fill | <div> (only child of .progress) | The inner fill bar. Set width inline (style="width: 60%;") or via JS. Transitions across 0.24 s ease so updates animate smoothly. |
| .progress-sm / .progress-md | .progress | Heights — Small (8 px, default) and Medium (12 px). Sizes map 1:1 to the Figma "Size" property. |
| .progress-brand | .progress | Default. Neutral black-on-white track (--progress-brand-bg) + black fill (--progress-brand-progress). Inverts to white-on-dark in dark mode. |
| .progress-blue / -green / -purple / -orange / -yellow / -red | .progress | Coloured variants — semi-transparent tinted track + solid progress fill. Each maps to its own --progress-{color}-{field} token triple. |
| .progress-indeterminate | .progress | Switches the fill from value-driven to a 1.4 s looped sweep animation. Use when duration is unknown; drop the modifier and set a real aria-valuenow as soon as you can measure progress. |
| role="progressbar" | .progress | ARIA role — always present. |
| aria-valuemin / aria-valuemax / aria-valuenow | .progress | Bounds + current value (0 / 100 / N). Required for determinate bars so screen readers announce progress. Omit aria-valuenow for indeterminate; pair with aria-label instead. |
| --progress-{color}-bg | Token | Track background. Semi-transparent tint (~20% alpha) of the progress colour for every variant except Brand, which uses black @ 10% (white @ 10% in dark). |
| --progress-{color}-border | Token | Track border. Transparent on every variant — exposed as a named token so a future outlined variant can swap it without forking the rule. |
| --progress-{color}-progress | Token | Solid fill colour for the inner bar. |