Progress

Displays an indicator showing the completion progress of a task, such as a file upload or a multi-step form.

Basic usage

Pass a value between 0 and 100 to set how full the bar is.

Values

The indicator animates to the supplied value. An empty bar is 0 and a full bar is 100. The track keeps a --control-edge border so the 100% mark — and the control itself at value={0} — stays visible against the page.

Tones

tone recolours the bar and its track to the same ink step — the bar in the ink, the track a 20% tint of it — so every tone keeps the same fill-versus-track structure; default is --primary-ink. Those pairs were measured on the high-contrast palette, where they run 4.25:1 to 6.52:1. The default palette differs in light mode: there --primary-ink is --primary gold #E8B824, so default reads 1.55:1 against its track and 1.73:1 against the page — a recorded trade-off of the approved build, not a component defect. Use success for a finished job, warning as a quota approaches its ceiling, and destructive once it is over.

The warning tone also cuts diagonal hazard stripes through the filled part. That is not decoration: Comitor's brand is gold and warning is yellow, so --warning-ink and --primary-ink collapse to the same colour on three of the package's four palettes. The stripes carry the signal as shape, so it survives greyscale and colour blindness — never strip them off in a className override.

Do not darken the bar to pass the measurement. 3.13.0 tried exactly that — the letter avatar's gold-600 bar on a gold-100 track — and 3.13.1 took it back: in a real interface the dark brown bar weighed more than everything around it. The package now writes the rule down for every filled part, a bar, a background or an arc: it keeps the colour of the approved palette, and the 1.73:1 above is accepted, not a bug to fix. When a bar has to read more clearly, print its value beside it (as in “With a label” below), pick a tone, or leave it to the high-contrast palette, where the same bar clears 3:1. Do not repaint it through className either: bg-gold-600 is a raw scale step, which the high-contrast palette cannot move. How the two palettes split that work is on Colours.

default
success
warning
destructive

Indeterminate

Leave value undefined while the total is still unknown. Radix marks the root data-state="indeterminate" and drops aria-valuenow; the package deliberately ships no sweep animation, so add one in your app or reach for Spinner when there is nothing to measure. For a ring instead of a bar — one whose indeterminate state does spin — use CircularProgress.

With a label

Progress bars carry no visible text on their own. Pair the bar with a heading and a percentage to give it context.

Uploading files72%

Variant helpers

progressTrackVariants and progressBarVariants are exported from @comitor/ui. Reach for them when you need a bar shape Radix cannot express — a stacked or segmented meter, for instance — so the custom markup inherits the same tokens instead of hand-picking colours.

Storage used40%

Props

PropTypeDefaultDescription
valuenumber | null—Current value, from 0 to max — the bar draws value / max, and a value outside that range is clamped (from 3.3.3), so past the limit is a full bar reading 100%. Omit it (or pass null) for the Radix indeterminate state, where the bar stays at 0.
tone'default' | 'success' | 'warning' | 'destructive''default'Recolours both the bar and its track to the matching ink step — default is --primary-ink, the brand gold itself on the default palette. warning additionally cuts hazard stripes through the bar, so it stays distinguishable without colour.
maxnumber100Maximum value the progress can reach. Inherited from the Radix Progress root. Before 3.3.3 the bar ignored it and drew value as a percentage while screen readers read value / max.
getValueLabel(value: number, max: number) => string—Builds the aria-valuetext string announced by screen readers.
classNamestring—Additional Tailwind classes merged onto the track — e.g. set a custom height with h-3.
...restProgressPrimitive.Root props—All Radix Progress root props are forwarded to the underlying element.

Accessibility

  • Built on Radix Progress, the root element has role="progressbar" with aria-valuenow, aria-valuemin, and aria-valuemax set automatically.
  • Provide an accessible name with aria-label or aria-labelledby pointing at a visible heading so screen readers can announce what is loading.
  • The filled part is painted with --primary-ink (or the tone's ink) rather than --primary, and the track carries a --control-edge border. That splits the two jobs WCAG 1.4.11 asks for: the border outlines the control against the page, the fill-versus-track pair carries the ratio. On the default palette the two gold tokens are the same colour, so the default bar stays under 3:1 there by decision; the high-contrast palette is where it clears it.
  • Tone is never the only signal. warning adds hazard stripes precisely because colour alone cannot separate it from default on the high-contrast and dark palettes (WCAG 1.4.1).
  • Stripes say “approaching the limit”, not what the limit is. Keep an Alert, a StatusPill, or a line of text-warning-ink next to the bar to spell out the threshold and the next step.
  • Avoid using a progress bar as the sole feedback for very long operations — pair it with a live region announcement when the value changes significantly.