Components
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, so every tone keeps the same fill-versus-track structure. 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.
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.
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.
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.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | null | — | Completion percentage from 0 to max. 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. warning additionally cuts hazard stripes through the bar, so it stays distinguishable without colour. |
max | number | 100 | Maximum value the progress can reach. Inherited from the Radix Progress root. |
getValueLabel | (value: number, max: number) => string | — | Builds the aria-valuetext string announced by screen readers. |
className | string | — | Additional Tailwind classes merged onto the track — e.g. set a custom height with h-3. |
...rest | ProgressPrimitive.Root props | — | All Radix Progress root props are forwarded to the underlying element. |
Accessibility
- Built on Radix Progress, the root element has
role="progressbar"witharia-valuenow,aria-valuemin, andaria-valuemaxset automatically. - Provide an accessible name with
aria-labeloraria-labelledbypointing at a visible heading so screen readers can announce what is loading. - The filled part is painted with
--primary-inkrather than--primary, and the track carries a--control-edgeborder. 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. - Tone is never the only signal.
warningadds hazard stripes precisely because colour alone cannot separate it fromdefaulton the high-contrast and dark palettes (WCAG 1.4.1). - Stripes say “approaching the limit”, not what the limit is. Keep an
Alert, aStatusPill, or a line oftext-warning-inknext 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.