Installation
Theme
Mode

Overlays & feedback

Progress

Shows how far along an operation is — an upload, an import, a multi-step setup, or a quota. Linear bars, circular rings, and segmented steps, each determinate or indeterminate.

$npx shadcn@latest add @orbit/progress

Live

A simulated import driving all three forms at once.

Importing tasks
72 of 600 imported
x
StagesStep 1 of 4
12%

Linear bars

The default. Four heights — xs 4px · sm 6px · md 8px · lg 12px — an optional label and percentage, and an indeterminate mode for unknown durations.

Sizes
x
x
x
x
Label & value
Importing tasks
412 of 600 imported
x
Sync complete
x
Indeterminate — a looping sweep, no aria-valuenow
x

Circular rings

For compact spots and dashboards. Four sizes — sm 40px · md 56px · lg 80px · xl 120px — with an optional centered percentage, plus a spinning indeterminate ring.

sm · 25%
68%
md · 68%
100%
lg · done
indeterminate

Steps & tones

Segmented steps for discrete flows like setup wizards. Tones carry status — green for done, amber for caution, red for a stalled or failing task, neutral for muted.

Steps
Account setupStep 2 of 4
MigrationStep 5 of 5
Tones
In progress
x
Complete
x
Storage used
x
Quota nearly full
x
Archived scope
x

Props

ProgressBar

PropTypeDefaultDescription
valuenumber0Current value, clamped to 0–max. Ignored while indeterminate.
maxnumber100Upper bound of the range.
size"xs" | "sm" | "md" | "lg""md"Track height: 4 / 6 / 8 / 12px.
tone"blue" | "green" | "amber" | "red" | "neutral""blue"Fill color intent, mapped to theme tokens.
indeterminatebooleanfalseLooping 1.3s sweep for unknown durations; omits aria-valuenow.
labelReactNodeHeader-row label; also names the bar for screen readers via the Base UI Label.
showValuebooleanfalsePercentage readout on the right of the header (hidden while indeterminate).
captionReactNodeMuted helper line under the track, e.g. “412 of 600 imported”.

ProgressRing

PropTypeDefaultDescription
valuenumber0Current value, clamped to 0–max.
maxnumber100Upper bound of the range.
size"sm" | "md" | "lg" | "xl""md"Diameter: 40 / 56 / 80 / 120px (stroke 4 / 5 / 6 / 8px).
tone"blue" | "green" | "amber" | "red" | "neutral""blue"Arc color intent.
indeterminatebooleanfalse0.9s spinning arc; omits aria-valuenow.
showValuebooleanfalseCentered percentage (hidden while indeterminate).

ProgressSteps

PropTypeDefaultDescription
valuenumber0Completed step count.
stepsnumber5Total number of segments.
tone"blue" | "green" | "amber" | "red" | "neutral""blue"Filled-segment color intent.
labelReactNodeHeader-row label; showing it also shows the “Step x of y” readout.

Usage

Do

Use indeterminate for unknown waits

When you can’t estimate duration, show the looping bar or spinning ring instead of a fake percentage.

Don’t

Animate a determinate bar backward

Progress should only move forward; jumping back reads as an error.

Do

Pair long bars with a count

“412 of 600 imported” tells the user more than a percentage alone.

Don’t

Use a tiny ring for a long task

For multi-minute work, a labeled bar with a count communicates far better than a small ring.

Keyboard & accessibility

Every form exposes the progressbar pattern: role=progressbar with aria-valuemin 0, aria-valuemax, and aria-valuenow — omitted while indeterminate so screen readers announce a busy state. The bar builds on Base UI Progress, so a label is wired up automatically; pass aria-label when there's no visible label (rings, bare bars). The steps form adds aria-valuetext (“Step 2 of 4”). All animations freeze under prefers-reduced-motion via the global guard.

Announced as “Importing tasks, 68%”
x