Components
Progress
See also: Spinner.
Indeterminate
<progress aria-busy="true"></progress>Determinate
<progress value="10" max="100"></progress>Variants
Use the modifier classes .filled, .default, or
.tonal on the <progress> element to swap the
progress bar track surface for better contrast on different backgrounds.
<progress class="progress default" value="25" max="100"></progress><progress class="progress filled" value="50" max="100"></progress><progress class="progress tonal" value="75" max="100"></progress>Accessibility
If the <progress> element is describing the loading progress
of a section of a page:
- use
aria-describedbyto point to the status -
set
aria-busy="true"on the section that is being updated, removing it when loading is finished.
Source: MDN
Content here is loading.
<div aria-busy="true" aria-describedby="progress-bar"> Content here is loading.</div><progress aria-label="Content loading…" class="progress" id="progress-bar"></progress>API
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Progress | <progress> | - | The native HTML progress element. |
| Indeterminate | No value attribute | - | Display an indeterminate loading state. |
| Variant | .filled, .default, .tonal | - | Modifiers for different background surfaces. |
Installation
@layer components.root { :where(progress) { --_accent-color: var(--primary); --_bg-color: var(--surface-tonal);
appearance: none; background-color: var(--_bg-color); block-size: var(--size-1); border: 0; border-radius: var(--border-radius, 0.25rem); display: inline-block; inline-size: 100%; overflow: hidden; position: relative; vertical-align: baseline;
/* Color */ &.filled { --_bg-color: var(--surface-filled); }
&.default { --_bg-color: var(--surface-default); }
&.tonal { --_bg-color: var(--surface-tonal); }
&::-webkit-progress-bar { background: none; border-radius: var(--border-radius, 0.25rem); }
&[value]::-webkit-progress-value { background-color: var(--_accent-color);
@media (prefers-reduced-motion: no-preference) { transition: inline-size 0.2s var(--ease-out-4, cubic-bezier(0, 0, 0.1, 1)); } }
&::-moz-progress-bar { background-color: var(--_accent-color); } }
@media (prefers-reduced-motion: no-preference) { progress:indeterminate { background-color: var(--_bg-color);
&::after { animation: indeterminate 2s linear infinite; background-color: var(--_accent-color); content: ""; inset: 0 auto 0 0; position: absolute; will-change: inset-inline-start, inset-inline-end; }
&[value]::-webkit-progress-value { background-color: transparent; }
&::-moz-progress-bar { background-color: transparent; } }
[dir="rtl"] { :where(progress):indeterminate { animation-direction: reverse;
&::after { animation-direction: reverse; } } } }
@keyframes indeterminate { 0% { inset-inline-start: -200%; inset-inline-end: 100%; }
60% { inset-inline-start: 107%; inset-inline-end: -8%; }
100% { inset-inline-start: 107%; inset-inline-end: -8%; } }}