Progress indicators

Progress indicators show the status of an ongoing process. Choose the shape that fits your layout. A linear indicator spans a width, a circular one fits a fixed square. Then choose the mode that matches what you know:

  • Determinate when you know how far along the process is. Pass a value.
  • Indeterminate when you do not. Pass indeterminate and no value.

Determinate

value is a fraction between 0 and max, which defaults to 1. Drag the slider below to see how the active indicator, the gap and the stop indicator respond.

<LinearProgress value={0.6} aria-label="Download progress" />
<CircularProgress value={0.6} aria-label="Download progress" />

Indeterminate

Use this while you wait for something whose duration you cannot predict. The indicator keeps looping until you either remove it or give it a value.

<LinearProgress indeterminate aria-label="Loading" />
<CircularProgress indeterminate aria-label="Loading" />

Wavy

The Material 3 expressive variant. Only the active indicator waves, the track stays smooth, and the wave travels one wavelength per second. A determinate LinearProgress flattens the wave at 10% and below and at 95% and above, so the ends stay readable. Drag the slider above past those points to see it happen.

<LinearProgress wavy value={0.6} />
<LinearProgress wavy indeterminate />
<CircularProgress wavy value={0.6} />
<CircularProgress wavy indeterminate />

Buffer

Linear only. buffer marks how much has already loaded ahead of the current position, as a streaming video would. Everything beyond the buffer is drawn as dots.

<LinearProgress value={0.4} buffer={0.85} />

Without a track

Set track=false when the indicator sits on top of another component that already provides a surface, such as a button's loading state. Both Button and IconButton do this for you when you pass loading.

<CircularProgress indeterminate track={false} />
<LinearProgress indeterminate track={false} />

Four colors

fourColor cycles the indicator through primary and tertiary tones instead of a single colour. Use it on indeterminate indicators, where the shifting colour helps convey that something is still happening.

<CircularProgress fourColor indeterminate />
<LinearProgress fourColor indeterminate />

Accessibility

Both components render role="progressbar" and keep aria-valuenow and aria-valuemax in sync with value and max. Neither has any text of its own, so always pass an aria-label saying what is loading. Indeterminate indicators leave out aria-valuenow, and that omission is what tells assistive technology the duration is unknown.

<CircularProgress
	indeterminate
	aria-label="Loading search results"
/>

wavy honors prefers-reduced-motion. With the preference set, the wave is dropped and the indicator falls back to its plain shape, while the spinner and the bar keep animating so they still read as busy.

Right-to-left

LinearProgress mirrors itself in a right-to-left context. The indicator grows from the right and the stop indicator moves to the left edge. There is nothing to configure, since it follows the inherited dir.

<div dir="rtl">
	<LinearProgress value={0.6} />
</div>

Theming

Circular progress tokens

TokenDefault value
--np-circular-progress-color--np-color-primary
--np-circular-progress-track-color--np-color-secondary-container
--np-circular-progress-active-indicator-width8.3333
--np-circular-progress-size3rem

--np-circular-progress-active-indicator-width is a unitless percentage of the indicator size, so the stroke scales along with --np-circular-progress-size. The gap between the two lanes is derived from that width, which keeps it constant however thick the stroke gets: 4.8dp, and 4dp for the wavy variant.

Circular progress example

<CircularProgress
	--np-circular-progress-color="var(--np-color-error)"
	--np-circular-progress-track-color="var(--np-color-error-container)"
	--np-circular-progress-active-indicator-width="20"
	--np-circular-progress-size="5rem"
	indeterminate
/>

Linear progress tokens

TokenDefault value
--np-linear-progress-track-shape--np-shape-corner-full
--np-linear-progress-track-height0.25rem
--np-linear-progress-active-indicator-height0.25rem
--np-linear-progress-active-indicator-color--np-color-primary
--np-linear-progress-track-color--np-color-secondary-container
--np-linear-progress-track-gap0.25rem
--np-linear-progress-wave-height0.625rem

--np-linear-progress-wave-height only applies to the wavy variant, which needs a taller container to fit the crests.

Linear progress example

<LinearProgress
	--np-linear-progress-active-indicator-color="var(--np-color-error)"
	--np-linear-progress-track-color="var(--np-color-error-container)"
	--np-linear-progress-track-shape="0.5rem"
	--np-linear-progress-track-height="0.5rem"
	--np-linear-progress-active-indicator-height="0.5rem"
	indeterminate
/>

API

Both components take the same attributes, apart from buffer, which is linear only.

Circular progress attributes

AttributeTypeDefaultDescription
valuenumber0Progress to display, a fraction between 0 and max
maxnumber1Maximum progress to display, defaults to 1.
indeterminatebooleanfalseWhether or not to display indeterminate progress, which gives no indication to how long an activity will take.
fourColorbooleanfalseWhether or not to render indeterminate mode using 4 colors instead of one.
trackbooleantrueWhether or not to render the inactive track. Set to false for indicators layered on another component, such as a button's loading state.
wavybooleanfalseWhether or not to draw the active indicator as a travelling wave, per M3 expressive.

Linear progress attributes

AttributeTypeDefaultDescription
valuenumber0Progress to display, a fraction between 0 and max
maxnumber1Maximum progress to display, defaults to 1.
indeterminatebooleanfalseWhether or not to display indeterminate progress, which gives no indication to how long an activity will take.
fourColorbooleanfalseWhether or not to render indeterminate mode using 4 colors instead of one.
trackbooleantrueWhether or not to render the inactive track. Set to false for indicators layered on another component, such as a button's loading state.
wavybooleanfalseWhether or not to draw the active indicator as a travelling wave, per M3 expressive.
buffernumber0Buffer amount to display, a fraction between 0 and max. If the value is 0 or negative, the buffer is not displayed.