Linear progress indicator

A linear progress indicator shows how far a task has got, or that it is still running, along a horizontal bar. Give it a value and the bar fills to it; leave it looping when the wait has no known length. Below, flat and wavy bars fill and loop side by side, and a few switch on their own.

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 shape and thickness decide how it looks. Pick the mode first:

  • Determinate: a task that reports how far it has got, such as a file upload. 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 bar suits most waits; a bar with a moving wave suits products that use the Material 3 Expressive look. Set @waveShape.
  • Standard or thick: a heavier track draws more attention to a wait. Set thickness.

Built in⁠

  • value is clamped between 0 and max, so a value that overshoots cannot run past the end.
  • A new value eases in over 250 milliseconds, and immediate turns the easing off for values that already move smoothly.
  • hide fades the indicator out instead of removing it.
  • wave-start and wave-end limit the wave to the stretch of progress between them.
  • thickness and @waveShape take their defaults from the style configuration.

Using indicators well⁠

  • Report real progress when the task can: use a determinate indicator, and keep an indeterminate one for a wait of unknown length.
  • Place the bar at the edge of what is loading, such as the top of a card or a page. For a compact spot, such as inside a button, use a Circular progress indicator instead.
  • Show one indicator per wait, rather than several for one operation.
  • Choose wavy or thick where the extra presence earns its space.
  • When the shape of the arriving content is known, show a Skeleton in its place instead of a bar.

These rules follow Material 3 Expressive's guidance for progress indicators, on material.io.

Determinate⁠

Set value to show how far a task has got. The value runs from 0 to max, which is 1 unless you set it, so value="65" with no max shows a full bar. Set max="100" to count in percent, or pass a fraction.

Indeterminate⁠

Set indeterminate when the task cannot say how long it will take. The bar then loops until you clear the setting. The indicator keeps its value, so a task can switch to determinate once it learns its length.

Thickness⁠

thickness sets the track's height: standard or thick. Omit it and the indicator takes the thickness from your style configuration, which is standard unless you have changed it. A thick track is 8 pixels high.

Wave shape⁠

@waveShape draws the bar flat (flat) or with a moving wave (wavy). Omit it and the indicator takes the shape from your style configuration, which is flat unless you have changed it.

Wave region⁠

On a wavy bar, wave-start and wave-end are positions from 0 to 1. Between them the bar waves, and outside them it runs flat; the defaults are 0.1 and 0.9. Move the value to watch the wave come and go.

Immediate updates⁠

A new value normally eases in over 250 milliseconds, which makes a value that arrives in steps read as continuous motion. Set immediate when the value is already continuous, such as a scroll position, so the bar never trails the real value.

Hiding⁠

hide fades the indicator out over 250 milliseconds and stops an indeterminate loop. The element keeps its space in the layout and stays a progress bar for assistive technology. The hidden attribute takes it out of both.

In a card⁠

A linear indicator along the top edge of a card shows that the card's content is on its way. Name the indicator for the task, and let the card's own text say the outcome.

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 Immediate updates.
indeterminateindeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Indeterminate.
maxmaxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Determinate.
thicknessthicknessstandard, thickProgressTrackThicknessProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
valuevaluenumberProgress to display, from 0 to max. Clamped to that range. See Determinate, Indeterminate, Immediate updates.
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 region.
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 region.

Changing max does not re-clamp an existing value; only the next write to value does.

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 Immediate updates.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Indeterminate.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Determinate.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Determinate, Indeterminate, Immediate updates.
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 region.
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 region.

Changing max does not re-clamp an existing value; only the next write to value does.

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 Immediate updates.
Indeterminatebool?default falseShows progress with no known end, for an activity whose duration is unknown. See Indeterminate.
Maxdouble?default 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Determinate.
ThicknessProgressTrackThickness?ProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
Valuedouble?Progress to display, from 0 to Max. Clamped to that range. See Determinate, Indeterminate, Immediate updates.
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 region.
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 region.

Changing max does not re-clamp an existing value; only the next write to value does.

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 Immediate updates.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Indeterminate.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Determinate.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Determinate, Indeterminate, Immediate updates.
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 region.
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 region.

Changing max does not re-clamp an existing value; only the next write to value does.

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 Immediate updates.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Indeterminate.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Determinate.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Determinate, Indeterminate, Immediate updates.
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 region.
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 region.

Changing max does not re-clamp an existing value; only the next write to value does.

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 Immediate updates.
indeterminatebooleandefault falseShows progress with no known end, for an activity whose duration is unknown. See Indeterminate.
maxnumberdefault 1The value at which progress is complete. A value below 0.001 is treated as 0.001. See Determinate.
thicknessProgressTrackThicknessTypeProgressTrackThickness.Standard, .Thickdefault ProgressTrackThickness.Standard, from the style configurationSets how thick the indicator's line is. See Thickness.
valuenumberProgress to display, from 0 to max. Clamped to that range. See Determinate, Indeterminate, Immediate updates.
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 region.
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 region.

Changing max does not re-clamp an existing value; only the next write to value does.

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-linear-progress-standard-track-thickness, which defaults to 4px.

Thickness⁠

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

Other tokens⁠

These stay the same whatever the thickness.

TokenValue
--ct-linear-progress-active-indicator-color--ct-sys-color-primary --ct-linear-progress-active-indicator-color
--ct-linear-progress-stop-indicator-size4px --ct-linear-progress-stop-indicator-size
--ct-linear-progress-track-color--ct-sys-color-secondary-container --ct-linear-progress-track-color
--ct-linear-progress-track-indicator-space4px --ct-linear-progress-track-indicator-space
--ct-linear-progress-wave-amplitude3px --ct-linear-progress-wave-amplitude
--ct-linear-progress-wave-wavelength40px --ct-linear-progress-wave-wavelength

Names and states⁠

A linear progress indicator is exposed to assistive technology as a progress bar and follows the WAI-ARIA Authoring Practices guidance on meters, gauges, and progress indicators.

  • A screen reader announces a range from 0 to max and the current value. An indeterminate indicator announces no current value.
  • The announced value is the clamped value in max units, not a percentage.
  • The indicator has no default name. Give every one an aria-label that says what is progressing.
  • Only aria-label names the indicator. aria-labelledby, aria-describedby, and aria-valuetext have no effect.
  • A hidden indicator is still a progress bar for assistive technology unless it is removed from the page or marked hidden; see Hiding.
  • The indicator is a progress bar, not a live region, and the indicator fires no events. Announce completion yourself, in a live region of your own.
  • A compact spot suits a Circular progress indicator, which names itself the same way. Content that has not arrived yet suits a Skeleton, which has a default name.

Keyboard and focus⁠

Key Action
None The indicator takes no keyboard input.
  • The indicator is not focusable and shows no focus ring.
  • To let a keyboard user act on a wait, such as canceling an upload, give the page a button for it.

Pointer and touch⁠

  • The indicator takes no pointer input, so a click passes through to whatever sits beneath it.
  • It has no touch target, so WCAG 2.5.8 Target Size (Minimum) has nothing to measure.

Display settings⁠

  • Under forced colors, the indicator takes a 1 pixel outline in the system text color.
  • With reduced motion requested, a wavy bar's wave holds still, and the easing of a new value completes at once.

Standards⁠

With its defaults, a linear 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): the role and values are built in, so set an aria-label for the name.
  • 4.1.3 Status Messages (AA): announce completion in a live region of your own, since the indicator fires no event.