Progress circle
Circular indicator of completion. Use when a ring reads better than a bar — compact dashboards, completion meters, single-value tiles.
ProgressCircle is the circular sibling of ProgressBar — same measurable 0–100 value, drawn as a ring instead of a bar. Reach for it when the layout favors a compact circle over a horizontal bar: dashboard tiles, completion meters, or a percentage that sits inside its own footprint. For unmeasurable loading, use Spinner.
Use it for
- Dashboard completion tiles ("Onboarding 72%")
- Compact single-value progress where a bar would waste horizontal space
- Score / goal rings with a centered percentage or custom label
- Known-eventual operations that briefly need an indeterminate spin
Import
import { ProgressCircle } from '@brikdesigns/bds';Variants
Default
value is a number 0–100. Pass showValue to render the percentage in the center.
<ProgressCircle value={72} showValue label="Onboarding completion" />Sizes
sm (64px), md (96px, default), lg (128px). Stroke width scales with the diameter.
<ProgressCircle value={72} size="sm" showValue label="Compact" />
<ProgressCircle value={72} size="md" showValue label="Default" />
<ProgressCircle value={72} size="lg" showValue label="Prominent" />Status
status recolors the fill stroke via canonical status tokens — default, positive, warning, negative.
<ProgressCircle value={100} status="positive" showValue label="Complete" />
<ProgressCircle value={40} status="warning" showValue label="Low" />
<ProgressCircle value={15} status="negative" showValue label="Critical" />Custom center content
showValue also accepts a ReactNode — pair the percentage with a sub-label instead of the plain ${value}% default.
<ProgressCircle
value={70}
size="lg"
label="Tasks complete"
showValue={
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: 'var(--heading-md)', fontWeight: 'var(--font-weight-bold)' }}>70%</div>
<div style={{ fontSize: 'var(--body-sm)', color: 'var(--text-secondary)' }}>of 200</div>
</div>
}
/>Indeterminate
indeterminate renders a continuous spin for unknown-duration progress. value is ignored and aria-valuenow is dropped in favor of aria-busy.
<ProgressCircle value={0} indeterminate label="Loading" />Custom fill color
fillColor is an escape hatch that overrides the status-token stroke. Prefer status for semantic color; reach for fillColor only for one-off brand-coded rings.
<ProgressCircle value={60} fillColor="var(--background-brand-primary)" showValue label="Brand progress" />When not to use
Don't use ProgressCircle for unmeasurable loading. If you can't compute a percentage, use Spinner. The indeterminate mode is for a measurable task that momentarily lacks a value (e.g. waiting on the first byte) — not as a permanent spinner substitute.
- Don't use ProgressCircle for multi-step flows. Step position is ProgressStepper; ProgressCircle is a single 0–100 value.
- Don't use it for a rating or score gauge. A horizontal gauge bar for scores is Meter.
Accessibility
- Renders a
<div role="progressbar">witharia-valuemin="0",aria-valuemax="100", andaria-valuenowset to the clamped value. - In
indeterminatemode,aria-valuenowis omitted andaria-busy="true"is set so assistive tech announces the pending state. - Always pass
label— it becomes the accessible name. The centeredshowValuecontent is decorative; the SVG isaria-hidden.
API
| Prop | Type | Default |
|---|---|---|
value | number (0–100) (required) | — |
size | 'sm' | 'md' | 'lg' | 'md' |
status | 'default' | 'positive' | 'warning' | 'negative' | 'default' |
label | string | — |
showValue | ReactNode (true renders the percentage) | — |
indeterminate | boolean | false |
fillColor | string | status token stroke |
Plus all standard <div> HTML attributes (excluding role and children, which ProgressCircle owns).
Related
- ProgressBar — same value, drawn as a linear bar
- ProgressStepper — multi-step flow position, not a single value
- Spinner — for indeterminate loading with no measurable value
- Meter — horizontal gauge for scores and ratings
- Storybook playground