A thin well that fills with ink as work completes.
On this page
Progress shows how much of a task is done. Use .progress on a native <progress>: the browser reports the value to assistive technology, and the class draws a thin well that fills with ink. For work of unknown length inside a control, use a spinner.
Progress
<labelclass="field">Uploading 3 of 5 files<progressclass="progress"value="62"max="100">62%</progress></label>
progress-segmented cuts the track into equal pieces, for progress that is a count of things: three of five steps, four of eight uploads. Set --progress-steps to the same number as max, so a piece is a step. The cut is a mask over the well and its fill alike, which keeps the pieces in step with the value.
Segmented
<labelclass="field">Step 3 of 5<progressclass="progress progress-segmented"max="5"value="3">Step 3 of 5</progress></label><labelclass="field">5 of 8 files uploaded<progressclass="progress progress-segmented progress-lg"style="--progress-steps: 8"max="8"value="5">5 of 8</progress></label>
progress-ring draws the same amount around a circle, for a tile, a row or the corner of a card. It is an element with role="progressbar". Where the browser supports typed attr(), the ring reads aria-valuenow and aria-valuemax itself, so the amount is written once, for people and for the drawing, and the arc eases to each new value. Elsewhere, set --progress-ring-value in a style attribute as well.
The element's own content is the label in the middle. Both ends of the arc are round, and an empty ring is an empty track.
Ring
<divclass="progress-ring progress-ring-sm"role="progressbar"aria-label="Upload"aria-valuenow="40"></div><divclass="progress-ring"role="progressbar"aria-label="Storage used"aria-valuenow="64">64</div><divclass="progress-ring progress-ring-lg"role="progressbar"aria-label="Steps done"aria-valuenow="3"aria-valuemax="8"aria-valuetext="3 of 8">3/8</div><divclass="progress-ring progress-ring-xl"role="progressbar"aria-label="Coverage"aria-valuenow="86">86%</div>
Without aria-valuenow the amount is unknown, and a quarter arc travels the track. Set --progress-ring-color to a status color when the ring reports one, and say the status in words beside it.
The bar does not print its number. Put it beside the label in tabular figures so it does not shift as it counts.
With a value
<divclass="flexflex-colgap-xs"><divclass="flexitems-baselinejustify-betweentext-sm"><spanclass="fg-text-strong"id="storage-label">Storage</span><spanclass="fg-text-muted">7.4 of 10 GB</span></div><progressclass="progress"value="7.4"max="10"aria-labelledby="storage-label">74%</progress></div>
A progress bar, on a native progress element with a label: a 6px track that fills with ink and eases to each new value. The text inside the element is a fallback
progress-sm
A 4px track, for a row in a list; the default is 6px. With progress
progress-lg
An 8px track; the default is 6px. With progress
progress-segmented
The track in --progress-steps equal pieces, five by default, for a count of things. Set --progress-steps to the same number as max. With progress
progress-ring
A ring, 40px across, on an element with role="progressbar", an accessible name and the amount in aria-valuenow. The element's own content is the label in the middle
progress-ring-sm
A 20px ring; the default is 40px. With progress-ring
progress-ring-lg
A 64px ring; the default is 40px. With progress-ring
progress-ring-xl
A 96px ring with a larger figure in the middle; the default is 40px. With progress-ring
/* * Progress: a native <progress> drawn as a thin well that fills with ink. * Without a value it is indeterminate: a band of ink travels along the track. * A ring draws the same amount around a circle, for a tile, a row or the corner of a card. */@property--progress-ring-value{syntax:'<number>';inherits: true;initial-value:0;}@layer components {.progress{--progress-height:.375rem;--progress-color:var(--color-surface-inverse);display:block;width:100%;height:var(--progress-height);margin:0;border:0;border-radius:999px;overflow:hidden;background:var(--color-surface-inset);box-shadow:var(--shadow-pressed);vertical-align:middle;appearance:none;&::-webkit-progress-bar{background:transparent;}/* The fill keeps a round end and eases to each new value. */&::-webkit-progress-value{border-radius:999px;background:var(--progress-color);transition: inline-size var(--duration-base)var(--easing-glide);}&::-moz-progress-bar{border-radius:999px;background:var(--progress-color);}&:indeterminate{background:linear-gradient(90deg,transparent,var(--progress-color)30%,var(--progress-color)70%,transparent)00/40%100%no-repeat,var(--color-surface-inset);/* Linear: an eased loop would rest at its ends, where the band is outside the track. */animation: progress-travel 1.2slinearinfinite;}&:indeterminate::-webkit-progress-value{background:transparent;}&:indeterminate::-moz-progress-bar{background:transparent;}&.progress-sm{--progress-height:.25rem;}&.progress-lg{--progress-height:.5rem;}/* * Segmented: the track is cut into --progress-steps equal pieces, for a count of things: four of five * steps, three of four checks. The cut is a mask over the well and its fill alike, so the pieces stay * in step with each other; their ends are square and the track's own corner is small to match. */&.progress-segmented{--progress-steps:5;--progress-gap:3px;border-radius:1.5px;/* A piece that is still empty is counted too, so the well takes a tint of the fill and holds on any surface. */background:color-mix(in oklab,var(--progress-color)20%,var(--color-surface-inset));mask:linear-gradient(90deg,blackcalc(100%-var(--progress-gap)),transparent0)00/calc((100%+var(--progress-gap))/var(--progress-steps))100%;&::-webkit-progress-value{border-radius:0;}&::-moz-progress-bar{border-radius:0;}}@media(prefers-reduced-motion:reduce){&::-webkit-progress-value{transition:none;}/* Without travel, an even half tone says the amount is unknown. */&:indeterminate{background:color-mix(in oklab,var(--progress-color)30%,var(--color-surface-inset));animation:none;}}@media(forced-colors:active){--progress-color: Highlight;outline:1pxsolid CanvasText;outline-offset:-1px;forced-color-adjust:none;background: Canvas;}}/* * Ring: an element with role="progressbar". Where the browser supports typed attr(), the ring reads * aria-valuenow and aria-valuemax itself, so the amount is written once, for people and for the drawing; * elsewhere set --progress-ring-value. Both ends of the arc are round, and the arc eases to each new value. * Without aria-valuenow the amount is unknown: a quarter arc travels the track. * The element's own content is the label in the middle. */.progress-ring{--progress-ring-size:2.5rem;--progress-ring-width:max(2px,calc(var(--progress-ring-size)/10));--progress-ring-color:var(--color-surface-inverse);--progress-ring-track:color-mix(in oklab,var(--progress-ring-color)11%,transparent);--progress-ring-max:100;--progress-ring-turn:calc(var(--progress-ring-value)/var(--progress-ring-max));position:relative;display:inline-grid;flex:none;place-items:center;width:var(--progress-ring-size);height:var(--progress-ring-size);color:var(--color-text-strong);font:var(--font-weight-control)calc(var(--progress-ring-size)*.27)/1var(--font-family-sans);font-variant-numeric:tabular-nums;letter-spacing:-.01em;vertical-align:middle;transition: --progress-ring-value var(--duration-base)var(--easing-glide);@supports(x:attr(x type(*))) {&[aria-valuenow]{--progress-ring-value:attr(aria-valuenow type(<number>),0);}&[aria-valuemax]{--progress-ring-max:attr(aria-valuemax type(<number>),100);}}/* * The drawing: an arc from a conic gradient, a dot at each end to round it, and a mask that keeps the ring. * The dots have no radius at zero, so an empty ring is an empty track. */&::before{--progress-ring-radius:calc((var(--progress-ring-size)-var(--progress-ring-width))/2);--progress-ring-cap:calc(var(--progress-ring-width)/2*min(1,var(--progress-ring-turn)*200));content:'';position:absolute;inset:0;border-radius:999px;background:radial-gradient(circleat50%calc(var(--progress-ring-width)/2),var(--progress-ring-color)calc(var(--progress-ring-cap)-.5px),transparentvar(--progress-ring-cap)),radial-gradient(circleatcalc(50%+var(--progress-ring-radius)*sin(var(--progress-ring-turn)*360deg))calc(50%-var(--progress-ring-radius)*cos(var(--progress-ring-turn)*360deg)),var(--progress-ring-color)calc(var(--progress-ring-cap)-.5px),transparentvar(--progress-ring-cap)),conic-gradient(var(--progress-ring-color)calc(var(--progress-ring-turn)*360deg),var(--progress-ring-track)0);mask:radial-gradient(farthest-side,transparentcalc(100%-var(--progress-ring-width)-.5px),blackcalc(100%-var(--progress-ring-width)),blackcalc(100%-.5px),transparent);}&:not([aria-valuenow]){--progress-ring-value:25;--progress-ring-max:100;&::before{animation: progress-ring-travel .9slinearinfinite;}}&.progress-ring-sm{--progress-ring-size:1.25rem;--progress-ring-width:2.5px;}&.progress-ring-lg{--progress-ring-size:4rem;--progress-ring-width:5px;}&.progress-ring-xl{--progress-ring-size:6rem;--progress-ring-width:6px;font-size:1.375rem;letter-spacing:-.02em;}@media(prefers-reduced-motion:reduce){transition:none;&:not([aria-valuenow])::before{animation-duration:2.4s;}}@media(forced-colors:active){--progress-ring-color: Highlight;--progress-ring-track: GrayText;forced-color-adjust:none;}}}@keyframes progress-ring-travel {to{rotate:360deg;}}@keyframes progress-travel {from{background-position:-67%0,00;}to{background-position:167%0,00;}}