Progress
Shows how far a task has gone, like an upload, an export or a setup flow. For a measurement that just sits in a range, such as storage used, use Meter.
Installation
Set up Camaleo once (Installation), then import what you need. The skin you load styles it.
import { Progress } from "@camaleo/react";Anatomy
A root with a header (label and value) and a track with the fill. Every part has a data-slot you can target from CSS.
Examples
Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.
Unknown duration
When you can't measure the work yet, pass value={null}. The number disappears, a segment slides along the track (it pulses in place with reduced motion), and screen readers hear that the bar is busy, not stuck at 0%.
Stage by stage
Click through it. Naming the current stage in valueLabel tells people what is happening, not just how much is left.
Count instead of percent
Set max to the real total and show "16 of 20 photos". People understand items better than a percentage.
Steps in a setup flow
For a short wizard, value={3} with max={5} reads as "Step 3 of 5", which says how much is left.
What screen readers hear
valueLabel only changes the visible text. Pass getAriaValueText too, so "1.2 of 3 GB" is read as words and not as "40 percent".
- contract-signed.pdfDone
- site-photos.zip18 of 40 MB
- budget-2026.xlsxWaiting
A list of uploads
One bar per file, each labelled with the file name, so people can tell which one is done, which is running and which is waiting.
With a cancel action
Click it. Long tasks need a way out. After canceling, say what happened in a status message and offer to try again.
In context
Progress bars sit next to the task they track. These are whole pieces of UI you can copy, in the skin you picked.
Upload queue
Complete your profile
Add your phone number and confirm your company details to unlock invoicing.
Import contacts
contacts-crm.csv · 3,000 rows
Guidelines
"Downloading update 4.2" tells people what they are waiting for, and gives the bar its accessible name.
"Downloading" what? Without a name and a value, people can't decide whether to wait.
If you can't measure the work, use value={null} instead of guessing a number.
A timer that races to 99% and then waits breaks trust. People give up on a bar they don't believe.
Props
getAriaValueText so screen readers hear the same thing.Intl.NumberFormat when formatting the value.
Defaults to the user's runtime locale.min and max. null means the duration is unknown.Other Base UI progress root props and native <div> attributes pass through.
Styling hooks
Attributes
Tokens it reads
Color
Shape & size
Type & motion
This component only
Accessibility
- It renders role="progressbar" with aria-valuenow, aria-valuemin and aria-valuemax, and the label as its accessible name.
- Screen readers hear the percentage by default. When the visible value is a count or a size, pass getAriaValueText so both say the same thing.
- With value={null}, aria-valuenow is left out, which tells assistive tech the duration is unknown.
- Screen readers don't announce every change. When the task ends or fails, say so in a status message (role="status").