Progress
Shows how much of a task is done, such as an upload or storage that fills up. When the amount is not known yet, pass null and the bar slides. For a short wait with no amount, use Spinner.
States
Empty, partial, complete, and indeterminate. A null value has no amount, so the value text stays empty and the indicator slides.
Storage use
A bare bar named with aria-label, beside text that gives the real numbers. Use over the quota is capped at 100.
Upload list
A bar under each file that is sending, named after the file. getAriaValueText reads the sizes instead of a bare percent, and “Saving…” once every byte is sent.
Uploading 2 of 4…
Q3 board deck.pdf
Team offsite photos – Lisbon 2026 – final selects.zip
Interview notes.docx
logo-dark.png
Usage
import {
Progress,
ProgressLabel,
ProgressValue,
} from "@tulipfarm/sprout/progress";
<Progress value={40}>
<ProgressLabel>Progress</ProgressLabel>
<ProgressValue />
</Progress>
<Progress value={null}>
<ProgressLabel>Waiting</ProgressLabel>
<ProgressValue />
</Progress>Progress renders the track and indicator for you. Its children sit on one row above the track: ProgressLabel at the start andProgressValue at the end. The row gap is 8px and the track is 4px tall.
value: a number frommintomax(0–100 by default), ornullwhen the amount is unknown.formatandlocalechange how the value is written.ProgressValuealso takes a function child.ProgressTrackandProgressIndicatorare the partsProgressuses. Use them only to build your own bar.
Every part takes className (a string or a function of the state) and a Base UI render prop. The root, track, indicator, label, and value get data-progressing,data-complete, or data-indeterminate.
Bare bar
<Progress value={Math.min(100, percent)} aria-label="Workspace storage used" />
<Progress
value={Math.floor((sent / size) * 100)}
aria-label={`Uploading ${name}`}
getAriaValueText={() => `Uploading ${formatFileSize(sent)} of ${formatFileSize(size)}`}
/>With no children, the bar stands alone. Keep the real numbers in text next to it, and name it with aria-label.
Accessibility
The root is a progressbar with aria-valuemin,aria-valuemax, and aria-valuenow. AProgressLabel names it; otherwise passaria-label. getAriaValueText replaces the percent that a screen reader reads, for example with “Uploading 3.1 MB of 8.4 MB”. ProgressValue is hidden from screen readers, because the bar already reads the value.
While the value is null, aria-valuenow is left out. The width changes in 180ms. With reduced motion, the width jumps and the sliding bar becomes a faint full track.
Theme tokens
The track uses --sprout-secondary and the indicator--sprout-primary, so the bar takes the brand color in the TulipFarm theme. The label uses --sprout-text and the value--sprout-muted. In forced colors, the indicator isHighlight on an outlined track.