- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
A ring with the progress as a percentage.
"use client"
import * as React from "react"
import { CircularProgressCombined } from "@workspace/ui/components/circular-progress"
export function CircularProgressDemo() {
const [value, setValue] = React.useState(13)
React.useEffect(() => {
const timer = setTimeout(() => setValue(66), 500)
return () => clearTimeout(timer)
}, [])
return (
<CircularProgressCombined value={value} aria-label="Uploading results" />
)
}
Usage
Use circular progress for work in flight when space is tight: a file upload, a sync, results being processed. It fits beside a label, inside a button or in a card corner. Use a progress bar when there is room for one, and a gauge to show a measurement rather than a task.
Import it from @workspace/ui/components/circular-progress.
For the common case, CircularProgressCombined renders the indicator, track, range and value text for you.
Anatomy
- CircularProgress — The root. Holds the value and geometry, and has the
progressbarrole. - CircularProgressIndicator — The SVG that draws the ring. Put CircularProgressTrack and CircularProgressRange inside it.
- CircularProgressTrack — The full ring, in a muted colour.
- CircularProgressRange — The filled arc, up to the current value. It starts at the top and fills clockwise.
- CircularProgressValueText — The text centred over the ring. Defaults to a percentage.
Notes
- Give the root an
aria-labelso screen readers know what is loading. - Pass
getValueTextto change the text read by screen readers and shown by default. Pass children to CircularProgressValueText to change only what is shown. - Colour the fill with a text colour class on CircularProgressRange, for example
text-chart-2. The ring usescurrentColor. - The default value text is
text-sm. On small rings, shrink it or leave CircularProgressValueText out. - Keep
thicknesswell belowsize, or the ring will not draw properly. - The indeterminate spin turns off when the reader prefers reduced motion.
Examples
Sizes
Change size and thickness together so the ring keeps its weight.
"use client"
import { CircularProgressCombined } from "@workspace/ui/components/circular-progress"
export function CircularProgressSizes() {
return (
<div className="flex items-center gap-6">
<CircularProgressCombined
value={40}
size={80}
thickness={8}
className="[&_span]:text-[10px]"
aria-label="Small"
/>
<CircularProgressCombined value={60} aria-label="Default" />
<CircularProgressCombined
value={80}
size={200}
thickness={24}
className="[&_span]:text-3xl"
aria-label="Large"
/>
</div>
)
}
Custom value
Set max for a count that is not 0–100, colour the range, and pass children to CircularProgressValueText to show a count and caption.
"use client"
import {
CircularProgress,
CircularProgressIndicator,
CircularProgressRange,
CircularProgressTrack,
CircularProgressValueText,
} from "@workspace/ui/components/circular-progress"
export function CircularProgressCustomValue() {
return (
<CircularProgress
value={7}
max={12}
size={96}
thickness={6}
getValueText={(value, _min, max) => `${value} of ${max} markers`}
aria-label="Markers processed"
>
<CircularProgressIndicator>
<CircularProgressTrack />
<CircularProgressRange className="text-chart-2" />
</CircularProgressIndicator>
<CircularProgressValueText className="flex-col gap-0.5">
<span className="text-lg font-semibold tabular-nums">7/12</span>
<span className="text-[10px] text-muted-foreground">markers</span>
</CircularProgressValueText>
</CircularProgress>
)
}
Indeterminate
Set value={null} when you do not know how long the task will take. A quarter arc spins around the track.
"use client"
import { CircularProgressCombined } from "@workspace/ui/components/circular-progress"
export function CircularProgressIndeterminate() {
return <CircularProgressCombined value={null} aria-label="Loading" />
}
Props
These are the props you set most often. Unlisted props pass through to the underlying element.
CircularProgress
| Prop | Type | Default | Description |
|---|---|---|---|
value | number or null | null | Current value. null is indeterminate. Clamped to min–max. |
min | number | 0 | Lowest value. |
max | number | 100 | Highest value. |
getValueText | (value, min, max) => string | Percentage | Text for screen readers and the default CircularProgressValueText. |
size | number | 48 | Width and height in pixels. |
thickness | number | 4 | Stroke width of the ring. |
render | ReactElement or function | — | Replaces the root div with your own element. |
className | string | — | Classes merged onto the root. |
Data attributes
CircularProgressIndicator, CircularProgressTrack and CircularProgressRange set data-state to indeterminate, loading or complete, so you can style each state, for example data-[state=complete]:text-chart-2.