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⁠

BlazorReactWebOverviewExamplesAPIStylingAccessibility

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 value and 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⁠

  • value eases to each new value over 250 ms, so a download that reports in steps reads as continuous motion; immediate shows each value at once.
  • max sets what a full arc means, and a value outside 0 to max is clamped to that range.
  • indeterminate loops one arc that grows and shrinks.
  • @waveShape shows a moving wave along the arc, and wave-start and wave-end set where along it the wave is full strength.
  • thickness and track-shape set the arc's weight and the path it follows: a circle, a soft squircle, or a squircle.
  • hide fades the indicator out when the work is done, and stops a loop that is running.

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⁠

value is a fraction from 0 to max, and the arc fills to it. It eases to each new value, so report progress as often as you have it. Press a button to report a new value.

Maximum⁠

max defaults to 1 and sets what a full arc means. A value of 65 with no max is clamped to 1 and shows a full arc; set max to 100 or pass the fraction 0.65. The first indicator below is the fraction, the second sets max, and the third shows the mistake.

Looping⁠

indeterminate loops one arc for work with no known length. Set it back to false when progress becomes known, and the arc fills to value.

Thickness⁠

thickness takes standard or thick. Omit it and the indicator takes the thickness from your style configuration, which is standard unless you have changed it.

Track shape⁠

track-shape sets the path the arc follows: circle, soft-squircle, or squircle. Omit the attribute and the indicator takes the shape from your style configuration, which is circle unless you have changed it.

Wave shape⁠

@waveShape takes flat or wavy, and the wavy indicator looks slightly larger than the flat one. wave-start and wave-end are positions from 0 to 1 along the track: the wave is full strength between them and flat outside. They default to 0.1 and 0.9, and the third indicator narrows that to 0.3 and 0.7. Omit @waveShape and the indicator takes the shape from your style configuration, which is flat unless you have changed it.

Easing⁠

A determinate indicator eases to each new value over 250 ms, which makes a value that arrives in steps read as smooth. When the value is already continuous, such as a scroll position, easing only adds lag: set immediate to show each value at once. Press the buttons with the switch on and off to compare.

Hiding⁠

hide fades the indicator out over 250 ms and stops a loop. The indicator keeps its space and its role, so to remove it from the layout and the accessibility tree, use the hidden 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⁠

PropertyAttributeTypeDescription
hidehidebooleandefault falseFades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding.
immediateimmediatebooleandefault falsePaints 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.
indeterminateindeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Looping.
maxmaxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum.
thicknessthicknessstandard, thickProgressTrackThicknessProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
trackShapetrack-shapecircle, soft-squircle, squircleProgressTrackShapeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configurationSets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape.
valuevaluenumberProgress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing.
waveEndwave-endnumberdefault 0.9The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape.
waveShapewave-shapeflat, wavyProgressWaveShapeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configurationSets whether the indicator's line is flat or wavy. See Wave shape.
waveStartwave-startnumberdefault 0.1The 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 max leaves an existing value unclamped; only the next write to value clamps it.

Props⁠

PropTypeDescription
hidebooleandefault falseFades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding.
immediatebooleandefault falsePaints 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.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Looping.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
trackShapeProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configurationSets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing.
waveEndnumberdefault 0.9The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape.
waveShapeProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configurationSets whether the indicator's line is flat or wavy. See Wave shape.
waveStartnumberdefault 0.1The 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 max leaves an existing value unclamped; only the next write to value clamps it.

Parameters⁠

ParameterTypeDescription
Hidebool?default falseFades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding.
Immediatebool?default falsePaints 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.
Indeterminatebool?default falseShows progress with no known end, for an activity whose duration is unknown. See Looping.
Maxdouble?default 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum.
ThicknessProgressTrackThickness?ProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
TrackShapeProgressTrackShape?ProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configurationSets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape.
Valuedouble?Progress to display, from 0 to Max. Clamped to that range. See Value, Maximum, Looping, Easing.
WaveEnddouble?default 0.9The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape.
WaveShapeProgressWaveShape?ProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configurationSets whether the indicator's line is flat or wavy. See Wave shape.
WaveStartdouble?default 0.1The 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 max leaves an existing value unclamped; only the next write to value clamps it.

Inputs⁠

InputTypeDescription
hidebooleandefault falseFades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding.
immediatebooleandefault falsePaints 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.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Looping.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
trackShapeProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configurationSets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing.
waveEndnumberdefault 0.9The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape.
waveShapeProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configurationSets whether the indicator's line is flat or wavy. See Wave shape.
waveStartnumberdefault 0.1The 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 max leaves an existing value unclamped; only the next write to value clamps it.

Props⁠

PropTypeDescription
hidebooleandefault falseFades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding.
immediatebooleandefault falsePaints 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.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Looping.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
trackShapeProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configurationSets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing.
waveEndnumberdefault 0.9The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape.
waveShapeProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configurationSets whether the indicator's line is flat or wavy. See Wave shape.
waveStartnumberdefault 0.1The 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 max leaves an existing value unclamped; only the next write to value clamps it.

Props⁠

PropTypeDescription
hidebooleandefault falseFades the progress indicator out and stops an indeterminate loop. The element stays in the layout and in the accessibility tree. See Hiding.
immediatebooleandefault falsePaints 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.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Looping.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Value, Maximum.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
trackShapeProgressTrackShapeTypeProgressTrackShape.Circle, .SoftSquircle, .Squircledefault ProgressTrackShape.Circle, from the style configurationSets the outline the indicator's arc follows, from a circle to a rounder or squarer squircle. See Track shape.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Value, Maximum, Looping, Easing.
waveEndnumberdefault 0.9The progress (0–1) at which the wave ends. Above it the wave is flat. Applies only to a determinate wavy indicator. See Wave shape.
waveShapeProgressWaveShapeTypeProgressWaveShape.Flat, .Wavydefault ProgressWaveShape.Flat, from the style configurationSets whether the indicator's line is flat or wavy. See Wave shape.
waveStartnumberdefault 0.1The 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 max leaves an existing value unclamped; only the next write to value clamps it.

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⁠

Namestandardthick
track-thickness4px --ct-circular-progress-standard-track-thickness8px --ct-circular-progress-thick-track-thickness

Wave shape⁠

Nameflatwavy
size40px --ct-circular-progress-flat-size48px --ct-circular-progress-wavy-size

Other tokens⁠

These stay the same whatever the thickness and wave shape.

TokenValue
--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-space4px --ct-circular-progress-track-indicator-space
--ct-circular-progress-wave-amplitude1.6px --ct-circular-progress-wave-amplitude
--ct-circular-progress-wave-wavelength15px --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 max. It announces the current value while the indicator is determinate and no current value while indeterminate is set.
  • There is no default name, so a screen reader reads "progress bar" with no label. Give every indicator an aria-label that says what is progressing, such as "Uploading photos".
  • Only aria-label names the indicator. aria-labelledby, aria-describedby, and aria-valuetext have no effect.
  • hide fades the indicator and nothing else. A hidden indicator is still a progress bar, so use the hidden attribute 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 hide when the wait ends or offer a control that cancels it.
  • 4.1.2 Name, Role, Value (A): set aria-label on every indicator.
  • 4.1.3 Status Messages (AA): announce completion in a live region, since the indicator fires no event.