UI.MD

Progress

A progress bar, and the same progress as a ring, for showing completion toward a task.

Installation

$
npx shadcn@latest add https://ui.mattdowney.com/r/progress.json

Usage

import { Progress, ProgressRing } from "@/components/ui/progress"

Examples

Default

The indicator eases to its value (300ms ease-out). Remount via key to replay the fill from zero.

x

Ring

The same progress as a ring, for the places a full-width bar does not fit: a card corner, a row, a button's neighbor. It eases to its value the same way the bar does.

x

Ring sizes

Three sizes: 16, 24, and 48px. For anything larger, set the size with a className and pair it with the thin weight.

x
sm
x
default
x
lg

Ring weights

weight="thin" halves the stroke. Use it on a ring much larger than 48px, where the default stroke starts to look like a donut.

72%x
default
72%x
thin

Ring with a value

Children sit in the middle of the ring, out of the flow, so the box stays the size it was asked for. lg is sized for exactly this: a smaller ring leaves the label touching the arc.

72%x

API Reference

PropTypeDefaultDescription
valuenumber | null-Current progress between min and max. On the bar, omitting it (or passing null) is the indeterminate state: a pulsing one-third fill instead of an empty track. The ring has no such state and draws an empty track instead, because a ring is a quantity and a spinning one is a waiting state, which is a different thing. The bar's fill respects min/max and flips edges automatically in RTL.
sizeProgressRing"sm" | "default" | "lg""default"Ring diameter: 16, 24, or 48px. The stroke is a fixed ratio of it, so the three read as one ring. lg is sized to hold a number in the middle.
weightProgressRing"default" | "thin""default"Stroke as a ratio of the diameter: an eighth, or a sixteenth for thin. Use thin when sizing the ring past the shipped three with a className, where the default ratio reads as a donut.
childrenProgressRingReactNode-Content centered inside the ring, e.g. the percentage. Absolutely placed, so it never changes the ring's own size.
minnumber0Lower bound of the range.
maxnumber100The value at which the bar reads full. Drives both the visual fill and the value reported to assistive tech.
getValueLabel(value, max) => string-Overrides the accessible label announced for the current value.