progress indicator
The progress indicator comes in two variants and can be used to show a length of a process or express an unknown wait time, e.g. fetching a resource.
The first one is the determinate
variant, which is a completable progress bar for which you can set the value via the style. The second variant is the indeterminate
which is just a loading indicator for an unspecified wait time and therefore showing an animation only.
In order to make the component accessible each variant should provide an
aria-label
attribute or a label
element which needs to be set by the user.
To make the content accessible when using the progress
element to indicate the loading progress of a page section, the user should follow these steps:
- Set up an
aria-label
for theprogress
element, such as "Content loading..." - Set up an
aria-describedby
attribute with the same value as theprogress
element's ID in the content that is being loaded. - Set
aria-busy="true"
while the section is being loaded, and remove it once the content is fully loaded.
table of content
component variations
determinate progress indicator
<div class="a-progress-indicator-container">
<progress
class="a-progress-indicator -determinate"
id="content-progress"
value="37"
max="100"
></progress>
<div class="a-progress-indicator__inner-bar"></div>
</div>
indeterminate progress indicator
<div class="a-progress-indicator-container">
<progress class="a-progress-indicator -indeterminate" max="100"></progress>
<div class="a-progress-indicator__anim-bar">
<div class="a-progress-indicator__inner-bar"></div>
</div>
</div>
disabled progress indicator
<div class="a-progress-indicator-container">
<progress
class="a-progress-indicator -determinate -disabled"
value="37"
max="100"
></progress>
<div class="a-progress-indicator__inner-bar"></div>
</div>
indeterminate disabled progress indicator
<div class="a-progress-indicator-container">
<progress
class="a-progress-indicator -indeterminate -disabled"
max="100"
></progress>
<div class="a-progress-indicator__anim-bar">
<div class="a-progress-indicator__inner-bar"></div>
</div>
</div>
progress example
<div class="frontend-kit-example_progress-indicator">
<div class="a-progress-indicator-container">
<progress
class="a-progress-indicator -determinate"
id="random-progress"
max="100"
></progress>
<div class="a-progress-indicator__inner-bar"></div>
</div>
</div>
additional content
demo
// Add randomly between 2 to 10% progress.
function setProgress(container: Element): void {
let currentValue = Number(container.getAttribute('data-progress'));
if (currentValue === 100) {
currentValue = 0;
}
const progress: number = Math.floor(Math.random() * (10 - 2) + 5);
let newValue: number = currentValue + progress;
if (newValue > 100) {
newValue = 100;
}
container.setAttribute('data-progress', `${newValue}`);
}
export default (): void => {
const examples = document.querySelectorAll('#random-progress');
examples.forEach((container) => {
window.setInterval(setProgress.bind(this, container), 1000);
});
};
styles SCSS
$progress-indicator_indeterminate_width: 2rem;
$progress-indicator_height: 0.5rem;
@mixin dynamic-bar-animation-mixin {
@keyframes dynamic-bar-animation {
from {
transform: translateX(0);
}
to {
transform: translateX(
calc(100% - $progress-indicator_indeterminate_width)
);
}
}
}
.a-progress-indicator-container,
.a-progress-indicator__inner-bar,
progress {
height: $progress-indicator_height;
}
.a-progress-indicator-container {
min-width: 8rem;
overflow: hidden; // Firefox's styling support
position: relative;
}
progress {
appearance: none; // Safari's styling support
background-color: var(--minor-accent__enabled__fill__default);
border: 0; // Firefox support
box-shadow: inset 0 0 0 0.0625rem var(--minor-accent__enabled__front__default); // Firefox's styling support
display: block;
min-width: 8rem;
width: 100%;
// Chrome's styling support
&::-webkit-progress-bar {
background-color: var(--minor-accent__enabled__fill__default);
box-shadow: inset 0 0 0 0.0625rem
var(--minor-accent__enabled__front__default);
}
&::-webkit-progress-value {
background-color: var(--minor-accent__enabled__front__default);
}
// Firefox's styling support
&.-indeterminate::-moz-progress-bar {
background-color: var(--minor-accent__enabled__fill__default);
box-shadow: inset 0 0 0 0.0625rem
var(--minor-accent__enabled__front__default);
}
&.-disabled {
box-shadow: inset 0 0 0 0.0625rem
var(--minor-accent__disabled__front__default); // Firefox
// Chrome
&::-webkit-progress-bar {
background-color: var(--minor-accent__disabled__fill__default);
box-shadow: inset 0 0 0 0.0625rem
var(--minor-accent__disabled__front__default);
}
&::-webkit-progress-value {
background-color: var(--minor-accent__disabled__front__default);
}
// Firefox
&::-moz-progress-bar {
background-color: var(--minor-accent__disabled__front__default);
box-shadow: inset 0 0 0 0.0625rem
var(--minor-accent__disabled__front__default);
}
&.-indeterminate::-moz-progress-bar {
background-color: var(--minor-accent__disabled__fill__default);
}
+ .a-progress-indicator__anim-bar .a-progress-indicator__inner-bar {
background-color: var(--minor-accent__disabled__front__default);
}
}
}
.a-progress-indicator {
position: absolute;
transform: translateZ(0);
&__anim-bar {
animation: dynamic-bar-animation 2s infinite linear;
@include dynamic-bar-animation-mixin;
}
&.-indeterminate
+ .a-progress-indicator__anim-bar
.a-progress-indicator__inner-bar {
width: $progress-indicator_indeterminate_width;
}
&.-indeterminate.-disabled + &__anim-bar {
display: none;
}
&__inner-bar {
background-color: var(--minor-accent__enabled__front__default);
position: absolute;
}
}```