Circular progress indicator
A circular progress indicator shows how far a task has got, or that it is still running, in a compact spot. Whether you can report progress sets its mode: a value fills the arc, and no value loops it until the work ends. Watch the tiles below fill and loop, with two that switch between the modes on a timer.
Reference docs
Choosing a loading indicator
Three kinds of indicator tell the reader to wait. Each suits a different job:
- Linear progress indicator: how far a task has got, or that it is still running, on a bar across the content, such as a file upload.
- Circular progress indicator: the same, in a compact ring, such as inside a button while it saves.
- Skeleton: the shape of content that is still loading, such as gray lines where a list will appear.
Two jobs belong elsewhere. A count or status on an icon is a badge, and a message once the work is done is a toast.
Choosing a variant
The mode decides what a reader sees, and the other settings decide how it looks. Pick the mode first:
- Determinate: a task that reports how far it has got, such as a download. Set
andvalue .max - Indeterminate: a task with no known length, such as waiting for a server reply. Set
.indeterminate - Flat or wavy: a plain arc suits most waits; an arc with a moving wave suits products that use the Material 3 Expressive look. Set
@waveShape. - Standard or thick: a heavier arc draws more attention to a wait. Set
.thickness - Circle, soft squircle, or squircle: the path the arc follows, to match the corner shape of the surrounding controls. Set
.track-shape
Built in
eases to each new value over 250 ms, so a download that reports in steps reads as continuous motion;value shows each value at once.immediate sets what a full arc means, and amax outside 0 tovalue is clamped to that range.max loops one arc that grows and shrinks.indeterminate@waveShapeshows a moving wave along the arc, and andwave-start set where along it the wave is full strength.wave-end andthickness set the arc's weight and the path it follows: a circle, a soft squircle, or a squircle.track-shape fades the indicator out when the work is done, and stops a loop that is running.hide
Using indicators well
- Show a determinate indicator when you can report progress, and an indeterminate one only when you cannot.
- Put a circular indicator in a compact spot, such as inside a small control or alone in an empty region. Use a linear progress indicator for a task tied to a container or the page.
- Show one indicator per wait, whatever the number of steps.
- Reach for the wavy and thick shapes when you want Material 3 Expressive's look.
- Use a skeleton instead when you know the shape of the content that is arriving and the wait is short.
These rules follow Material 3 Expressive's guidance for progress indicators, on material.io.
Value
valuemax
Maximum
maxvaluemaxmaxmax
Looping
indeterminatevalue
Thickness
thicknessstandardthickstandard
Track shape
track-shapecirclesoft-squirclesquirclecircle
Wave shape
@waveShape takes flatwavywave-startwave-end@waveShape and the indicator takes the shape from your style configuration, which is flat
Easing
A determinate indicator eases to each new valueimmediate
Hiding
hidehidden attribute or remove it.
In context
An indicator suits a spot with room for little else, such as beside the text that says what is loading. Give it an aria-label that says the same. Switch the wait off and the arc settles at full.
Properties
| Property | Attribute | Type | Description |
|---|---|---|---|
hide | hide | booleandefault false | Fades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding. |
immediate | immediate | booleandefault false | Paints each new value at once, instead of easing to it over 250 ms. Set it when the value changes continuously, such as a scroll position: easing a value that is already smooth only makes the indicator trail the real one. See Easing. |
indeterminate | indeterminate | booleandefault false | Shows progress with no known end, for an activity whose duration is unknown. See Looping. |
max | max | numberdefault 1 | The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum. |
thickness | thicknessstandard, thick | ProgressTrackThicknessProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configuration | Sets how thick the indicator's line is. See Thickness. |
trackShape | track-shapecircle, soft-squircle, squircle | ProgressTrackShapeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configuration | Sets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape. |
value | value | number | Progress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing. |
waveEnd | wave-end | numberdefault 0.9 | The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
waveShape | wave-shapeflat, wavy | ProgressWaveShapeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configuration | Sets whether the indicator's line is flat or wavy. See Wave shape. |
waveStart | wave-start | numberdefault 0.1 | The progress (0–1) at which the wave begins. Below it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
A later change to maxvaluevalue
Props
| Prop | Type | Description |
|---|---|---|
hide | booleandefault false | Fades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding. |
immediate | booleandefault false | Paints each new value at once, instead of easing to it over 250 ms. Set it when the value changes continuously, such as a scroll position: easing a value that is already smooth only makes the indicator trail the real one. See Easing. |
indeterminate | booleandefault false | Shows progress with no known end, for an activity whose duration is unknown. See Looping. |
max | numberdefault 1 | The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum. |
thickness | ProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configuration | Sets how thick the indicator's line is. See Thickness. |
trackShape | ProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configuration | Sets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape. |
value | number | Progress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing. |
waveEnd | numberdefault 0.9 | The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
waveShape | ProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configuration | Sets whether the indicator's line is flat or wavy. See Wave shape. |
waveStart | numberdefault 0.1 | The progress (0–1) at which the wave begins. Below it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
A later change to maxvaluevalue
Parameters
| Parameter | Type | Description |
|---|---|---|
Hide | bool?default false | Fades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding. |
Immediate | bool?default false | Paints each new value at once, instead of easing to it over 250 ms. Set it when the value changes continuously, such as a scroll position: easing a value that is already smooth only makes the indicator trail the real one. See Easing. |
Indeterminate | bool?default false | Shows progress with no known end, for an activity whose duration is unknown. See Looping. |
Max | double?default 1 | The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum. |
Thickness | ProgressTrackThickness?ProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configuration | Sets how thick the indicator's line is. See Thickness. |
TrackShape | ProgressTrackShape?ProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configuration | Sets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape. |
Value | double? | Progress to display, from 0 to Max. Clamped to that range. See Value, Maximum, Looping, Easing. |
WaveEnd | double?default 0.9 | The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
WaveShape | ProgressWaveShape?ProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configuration | Sets whether the indicator's line is flat or wavy. See Wave shape. |
WaveStart | double?default 0.1 | The progress (0–1) at which the wave begins. Below it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
A later change to maxvaluevalue
Inputs
| Input | Type | Description |
|---|---|---|
hide | booleandefault false | Fades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding. |
immediate | booleandefault false | Paints each new value at once, instead of easing to it over 250 ms. Set it when the value changes continuously, such as a scroll position: easing a value that is already smooth only makes the indicator trail the real one. See Easing. |
indeterminate | booleandefault false | Shows progress with no known end, for an activity whose duration is unknown. See Looping. |
max | numberdefault 1 | The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum. |
thickness | ProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configuration | Sets how thick the indicator's line is. See Thickness. |
trackShape | ProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configuration | Sets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape. |
value | number | Progress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing. |
waveEnd | numberdefault 0.9 | The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
waveShape | ProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configuration | Sets whether the indicator's line is flat or wavy. See Wave shape. |
waveStart | numberdefault 0.1 | The progress (0–1) at which the wave begins. Below it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
A later change to maxvaluevalue
Props
| Prop | Type | Description |
|---|---|---|
hide | booleandefault false | Fades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding. |
immediate | booleandefault false | Paints each new value at once, instead of easing to it over 250 ms. Set it when the value changes continuously, such as a scroll position: easing a value that is already smooth only makes the indicator trail the real one. See Easing. |
indeterminate | booleandefault false | Shows progress with no known end, for an activity whose duration is unknown. See Looping. |
max | numberdefault 1 | The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum. |
thickness | ProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configuration | Sets how thick the indicator's line is. See Thickness. |
trackShape | ProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configuration | Sets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape. |
value | number | Progress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing. |
waveEnd | numberdefault 0.9 | The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
waveShape | ProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configuration | Sets whether the indicator's line is flat or wavy. See Wave shape. |
waveStart | numberdefault 0.1 | The progress (0–1) at which the wave begins. Below it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
A later change to maxvaluevalue
Props
| Prop | Type | Description |
|---|---|---|
hide | booleandefault false | Fades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding. |
immediate | booleandefault false | Paints each new value at once, instead of easing to it over 250 ms. Set it when the value changes continuously, such as a scroll position: easing a value that is already smooth only makes the indicator trail the real one. See Easing. |
indeterminate | booleandefault false | Shows progress with no known end, for an activity whose duration is unknown. See Looping. |
max | numberdefault 1 | The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum. |
thickness | ProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configuration | Sets how thick the indicator's line is. See Thickness. |
trackShape | ProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configuration | Sets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape. |
value | number | Progress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing. |
waveEnd | numberdefault 0.9 | The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
waveShape | ProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configuration | Sets whether the indicator's line is flat or wavy. See Wave shape. |
waveStart | numberdefault 0.1 | The progress (0–1) at which the wave begins. Below it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape. |
A later change to maxvaluevalue
Each attribute value has its own tokens; a cell shows its token's value, and selecting the cell shows the token's fallback path, with each name and value ready to copy. For example, the standard column's track-thickness row is --ct-circular-progress-standard-track-thickness, which defaults to 4px.
Thickness
| Name | standard | thick |
|---|---|---|
track-thickness | 4px --ct-circular-progress-standard-track-thickness | 8px --ct-circular-progress-thick-track-thickness |
Wave shape
| Name | flat | wavy |
|---|---|---|
size | 40px --ct-circular-progress-flat-size | 48px --ct-circular-progress-wavy-size |
Other tokens
These stay the same whatever the thickness and wave shape.
| Token | Value |
|---|---|
--ct-circular-progress-active-indicator-color | --ct-sys-color-primary --ct-circular-progress-active-indicator-color |
--ct-circular-progress-track-color | --ct-sys-color-secondary-container --ct-circular-progress-track-color |
--ct-circular-progress-track-indicator-space | 4px --ct-circular-progress-track-indicator-space |
--ct-circular-progress-wave-amplitude | 1.6px --ct-circular-progress-wave-amplitude |
--ct-circular-progress-wave-wavelength | 15px --ct-circular-progress-wave-wavelength |
Names and states
A circular progress indicator is exposed to assistive technology as a progress bar, as described in the WAI-ARIA Authoring Practices: progress and meter indicators guidance.
- A screen reader announces a range from 0 to
. It announces the currentmax while the indicator is determinate and no current value whilevalue is set.indeterminate - There is no default name, so a screen reader reads "progress bar" with no label. Give every indicator an
aria-labelthat says what is progressing, such as "Uploading photos". - Only
aria-labelnames the indicator.aria-labelledby,aria-describedby, andaria-valuetexthave no effect. fades the indicator and nothing else. A hidden indicator is still a progress bar, so use thehidehiddenattribute to take it out of the accessibility tree.- The indicator fires no events, so nothing marks completion. Announce the result yourself, for example in a live region.
Keyboard and focus
| Key | Action |
|---|---|
| None | The indicator is not focusable and responds to no keys. |
- The indicator is not interactive, so it shows no focus ring.
Pointer and touch
- The indicator is not a pointer target: clicks and taps pass through to what is behind it. WCAG 2.5.8 Target Size (Minimum) does not apply.
Display settings
- In forced colors, the indicator takes a 1 pixel outline in the system text color.
- With reduced motion requested, the wave holds still at its starting phase, and the remaining animations complete at once.
Standards
With its defaults, the circular progress indicator meets zero WCAG 2.2 success criteria on its own, because it takes no focus. Three depend on how you use it:
- 2.2.2 Pause, Stop, Hide (A): an indeterminate loop that runs for more than five seconds needs a way to stop, so set
when the wait ends or offer a control that cancels it.hide - 4.1.2 Name, Role, Value (A): set
aria-labelon every indicator. - 4.1.3 Status Messages (AA): announce completion in a live region, since the indicator fires no event.