Progress Bar

Atom

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

✅ Do
  • 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
❌ Don't
  • 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.

  1. 1Track.progress. Full-width pill-shaped container. Add colour modifier.
  2. 2Fill.progress-fill. Width = var(--pct) set as inline style on the track.
  3. 3Colour modifier.progress-brand / .progress-info etc. Seven semantic colours.
  4. 4Indeterminate.progress-indeterminate. CSS animation sweeps the fill back and forth. No --pct needed.

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.

Brand
Blue
Green
Purple
Orange
Yellow
Red

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%.

Small · 8
Medium · 12

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.

0%
25%
50%
75%
100%
Indeterminate

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).

0%
Value
Colour
Size

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.

Small (8 px)
0%
25%
50%
75%
100%
Medium (12 px)
0%
25%
50%
75%
100%

Accessibility

Attribute / BehaviourValueNotes
Rolerole="progressbar"Set on the .progress track element
Current valuearia-valuenow="65"Update dynamically as the value changes
Rangearia-valuemin="0" + aria-valuemax="100"Set the scale context for screen readers
Labelaria-label="Upload progress"Describe what is progressing — the bar alone has no context
IndeterminateOmit aria-valuenowWhen duration is unknown, remove aria-valuenow so screen readers announce it as indeterminate
CompletionAnnounce via live regionWhen progress reaches 100%, announce "Complete" via aria-live="polite"

API

Class / attrOnDescription
.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.progressHeights — Small (8 px, default) and Medium (12 px). Sizes map 1:1 to the Figma "Size" property.
.progress-brand.progressDefault. 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.progressColoured variants — semi-transparent tinted track + solid progress fill. Each maps to its own --progress-{color}-{field} token triple.
.progress-indeterminate.progressSwitches 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".progressARIA role — always present.
aria-valuemin / aria-valuemax / aria-valuenow.progressBounds + 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}-bgTokenTrack 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}-borderTokenTrack border. Transparent on every variant — exposed as a named token so a future outlined variant can swap it without forking the rule.
--progress-{color}-progressTokenSolid fill colour for the inner bar.