Determinate — flat
Active arc starts at 12 o'clock and sweeps clockwise to value%.
Default 40dp diameter / 4dp stroke; the 8dp sample is 44dp diameter.
40 / 4dp · 25%
40 / 4dp · 60%
44 / 8dp · 60%
64 / 4dp · 80%
120 / 4dp · 50%
Determinate — wavy
Active arc oscillates radially with 1.6dp amplitude and ~15dp wavelength along the arc length. Wavy diameters are slightly larger to give the wave room: 48dp (4dp) / 52dp (8dp). The wave's phase animates so it appears to flow along the arc.
48 / 4dp · 60%
52 / 8dp · 80%
96 / 4dp · 40%
160 / 4dp · 65%
Indeterminate
Outer rotation (~2s) plus a sweep that grows and shrinks (~1.3s); the offset cycle keeps the motion lively.
For short indeterminate processes (under 5s), prefer material-loading-indicator instead.
40 / 4dp flat
64 / 8dp flat
48 / 4dp wavy
96 / 4dp wavy
160 / 4dp wavy
In a button
Per spec § In buttons: replace the icon/label with the indicator while an action is pending. At very small sizes (≤24dp), use the flat shape — the wavy detail isn't visible.
Live demo — determinate slider
Drag to drive value on flat and wavy variants simultaneously.
Reduced motion + paused
prefers-reduced-motion: reduce freezes the animations. Toggle Rendering ▸ Emulate prefers-reduced-motion in DevTools.
paused attribute halts the rAF loop on demand.
Sample usage
<!-- Determinate flat (default 40dp / 4dp stroke) -->
<material-circular-progress value="60" label="Saving…"></material-circular-progress>
<!-- Determinate wavy, larger -->
<material-circular-progress value="60" wavy size="96" label="Saving…"></material-circular-progress>
<!-- Indeterminate (omit value) -->
<material-circular-progress label="Loading"></material-circular-progress>
<!-- In a button (small, flat) -->
<material-button variant="filled">
<material-circular-progress size="20" label="Saving"></material-circular-progress>
Saving…
</material-button>
<!-- Pause animation -->
<material-circular-progress wavy paused></material-circular-progress>