Linear trackers represent progress as the accumulation over time using a specific unit of measurement, such as dollars or months. To track progress measured in discrete units, use a segmented tracker. To track uninterrupted progress towards an end goal, use a continuous linear tracker.
Width = Variable depending on the container.
Max Number of Segments = 12
Segment Color = Gray 03 (default), Status - Success (active, customizable)
This tracker shows the progress of monthly payments, with each segment representing a month.
<div class="linear-tracker-segmented" id="demo-seg-linear">
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-label="January payment" class="progress-bar">
<div class="progress-track count-width"></div>
</div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-label="February payment" class="progress-bar">
<div class="progress-track count-width"></div>
</div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-label="March payment" class="progress-bar">
<div class="progress-track count-width"></div>
</div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-label="April payment" class="progress-bar">
<div class="progress-track count-width"></div>
</div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-label="May payment" class="progress-bar">
<div class="progress-track count-width"></div>
</div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="0" aria-label="June payment" class="progress-bar">
<div class="progress-track count-width"></div>
</div>
</div>
<div id="seg-linear-live" aria-live="polite" class="flex flex-justify-end legal-1 linear-tracker-label"></div>
<script>
const segLinearAlert = document.getElementById('seg-linear-live');
function demoSegLinear() {
let tracker = document.getElementById('demo-seg-linear');
if(!tracker) {
window.clearInterval(segLinearInterval);
return;
}
let progressBarList = tracker.querySelectorAll('.progress-bar');
let i = 0;
let interval = setInterval(function() {
progressBarList[i].setAttribute('aria-valuenow', '100');
if(segLinearAlert) {
segLinearAlert.innerHTML = progressBarList[i].getAttribute('aria-label') + ' complete';
}
i++;
if(i === progressBarList.length) clearInterval(interval);
}, 3000);
setTimeout(function() {
progressBarList.forEach(function(progBar) {
progBar.setAttribute('aria-valuenow', '0');
if(segLinearAlert) {
segLinearAlert.innerHTML = progBar.getAttribute('aria-valuenow') + '%';
}
})
}, 21000)
};
demoSegLinear();
const segLinearInterval = window.setInterval(demoSegLinear, 22000);
</script>Width = Variable depending on the container.
Success Text = Body 1, Gray 06
Tracker Text = Legal 2, Gray 06
Success Circle = Fill, Bright Blue; 1px border, White
Glyph = Check (large), White (complete)
This tracker shows the customers progress as they accumulate miles in pursuit of a defined goal. The color of the tracker can vary depending on the brand.
0 miles of miles
<div class="linear-tracker margin-1-t" id="demo-cont-linear">
<div class="tracker-alert" role="alert"></div>
<div
role="progressbar"
aria-valuemin="0"
aria-valuemax="20000"
aria-valuenow="0"
aria-label="Miles 0 from 20000"
aria-valuetext="0 miles"
data-percent="0"
class="progress-bar"
>
<div class="progress-track count-width">
<i class="glyph" data-dls-glyph="check" data-dls-glyph-size="md" data-dls-icon-role="decorative"></i>
</div>
</div>
<p class="legal-2 flex flex-justify-between pad-1-t">
<span id="left-label">0 miles</span>
<span id="right-label">
<span id="right-label-current-value">
<span id="current-value" aria-hidden="true"></span>
<span class="sr-only" id="sr-only-current-value" aria-live="polite"></span>
</span>
of
<span id="right-label-max-value"></span>
miles
</span>
</p>
</div>
<script>
const rightLabelCurrent = document.getElementById('right-label-current-value');
const rightLabelMax = document.getElementById('right-label-max-value');
const trackerAlert = document.querySelector('.tracker-alert');
const maxMiles = 20000;
rightLabelMax.innerText = maxMiles.toLocaleString('en-US');
function demoContLinear() {
let tracker = document.getElementById('demo-cont-linear');
if(!tracker) {
window.clearInterval(contLinearInterval);
return;
}
let progressBar = tracker.querySelector('.progress-bar');
let value = Number(progressBar.getAttribute('aria-valuenow'));
const maxValue = Number(progressBar.getAttribute('aria-valuemax'));
const minValue = Number(progressBar.getAttribute('aria-valuemin'));
// reset alert content so alert doesn't get read before completion
trackerAlert.innerHTML = "";
if(value >= maxValue) {
value = 0;
tracker.classList.remove('complete');
} else {
value += 2000;
// add content into the alert element to trigger the screen reader to read alert
if(value === maxValue){
tracker.classList.add('complete');
trackerAlert.innerHTML = '<p class="body-1 dls-gray-06 pad-1-b">You\'ve successfully earned back your miles!</p>';
}
}
progressBar.setAttribute('aria-valuenow', value);
// provide more context to the current value by including units
progressBar.setAttribute('aria-valuetext', `${value} miles`);
if(rightLabelCurrent) {
// adds commas to the number ex: 2000 --> 2,000
const formattedCurrentValue = value.toLocaleString('en-US');
// visually, only show current number
document.querySelector("span#current-value").innerHTML = formattedCurrentValue;
// include units for screen reades
document.querySelector("span#sr-only-current-value").innerHTML = `${formattedCurrentValue} miles`;
}
// display the correct progress bar width based on percentage complete
const percentage = Math.round((value / (maxValue - minValue)) * 100);
progressBar.setAttribute('data-percent', percentage)
};
demoContLinear();
const contLinearInterval = window.setInterval(demoContLinear, 6000);
</script>There are two types of loading indicators: determinate and indeterminate. For clarity and consistency, use only one indicator per operation or page load.
A determinate loading indicator is used when the percentage completion of an operation is available and can be calculated. For example, a loading progress meter (either linear or circular) which cstarts at 0 and reaches 100% upon completion.
An indeterminate loading indicator is used when the customer doesn’t need to know how long an operation or load will take, or when percentage completion data isn’t available. For example, a looping linear bar or circular spinner that stays animated until the operation is complete.
If the progress bar is describing the loading progress of a particular region of a page, use aria-describedby to point to the status, and set the aria-live=“polite” to announce it is finished loading.
Width = Variable (linear determinate and linear indeterminate)
Loading Bar Color = Gray 02 (default), Bright Blue (active)
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="60" aria-label="Linear determinate"
class="progress-bar" id="demo-linear">
<div class="progress-track count-width"></div>
</div>
<div id="linear-live" aria-live="polite" class="flex flex-justify-end legal-1"></div>
<script>
const linearAlert = document.getElementById('linear-live');
function demoLinear() {
let tracker = document.getElementById('demo-linear');
if(!tracker) {
window.clearInterval(linearInterval);
return;
}
let value = Number(tracker.getAttribute('aria-valuenow'));
const minValue = tracker.getAttribute('aria-valuemin');
const maxValue = tracker.getAttribute('aria-valuemax');
if(value >= maxValue) {
value = 0;
tracker.setAttribute('aria-valuenow', value);
if(linearAlert) {
linearAlert.innerHTML = tracker.getAttribute('aria-valuenow') + '%';
}
} else {
value += 10;
tracker.setAttribute('aria-valuenow', value);
if(linearAlert) {
linearAlert.innerHTML = tracker.getAttribute('aria-valuenow') + '%';
}
}
};
demoLinear();
const linearInterval = window.setInterval(demoLinear, 1000);
</script><div role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-label="Linear indeterminate"
class="progress-bar progress-indeterminate">
<div class="progress-track"></div>
</div>Min Size = 50x50px
Max Size = 70x70px
Progress Text = Body 3, Bright Blue, center-aligned
Circular Bar = 7px border; Gray 01 (default), Bright Blue (active)
<div class="flex">
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="50" aria-label="Large circle determinate"
class="progress-circle progress-determinate progress-lg margin-r" id="demo-cont-circ-lg">
<svg role="presentation" aria-hidden="true">
<circle cx="50%" cy="50%" r="45%" fill="none"></circle>
<circle cx="50%" cy="50%" class="count-stroke" r="45%"></circle>
</svg>
<div class="progress-value percent"></div>
</div>
<span id="cont-circ-lg-live" aria-live="polite" class="sr-only"></span>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="50" aria-label="Circle determinate"
class="progress-circle progress-determinate progress" id="demo-cont-circ">
<svg role="presentation" aria-hidden="true">
<circle cx="50%" cy="50%" r="45%" fill="none"></circle>
<circle cx="50%" cy="50%" class="count-stroke" r="45%"></circle>
</svg>
<div class="progress-value percent"></div>
</div>
<span id="cont-circ-live" aria-live="polite" class="sr-only"></span>
</div>
<script>
const contCircLgAlert = document.getElementById('cont-circ-lg-live');
const contCircAlert = document.getElementById('cont-circ-live');
function demoContCirc () {
let progressBarLg = document.getElementById('demo-cont-circ-lg');
let progressBar = document.getElementById('demo-cont-circ');
if(!progressBar) {
window.clearInterval(contCircInterval);
return;
}
let value = Number(progressBar.getAttribute('aria-valuenow'));
const minValue = progressBar.getAttribute('aria-valuemin');
const maxValue = progressBar.getAttribute('aria-valuemax');
if(value >= maxValue) {
value = 0;
progressBarLg.setAttribute('aria-valuenow', value);
progressBar.setAttribute('aria-valuenow', value);
if(contCircLgAlert) {
contCircLgAlert.innerHTML = progressBarLg.getAttribute('aria-valuenow') + '%';
} if(contCircAlert) {
contCircAlert.innerHTML = progressBar.getAttribute('aria-valuenow') + '%';
}
} else {
value += 25;
progressBarLg.setAttribute('aria-valuenow', value);
progressBar.setAttribute('aria-valuenow', value);
if(contCircLgAlert) {
contCircLgAlert.innerHTML = progressBarLg.getAttribute('aria-valuenow') + '%';
} if(contCircAlert) {
contCircAlert.innerHTML = progressBar.getAttribute('aria-valuenow') + '%';
}
}
};
demoContCirc();
const contCircInterval = window.setInterval(demoContCirc, 1000);
</script>Min Size = 20x20px
Max Size = 70x70px
Circular Bar = 7px border; Gray 01 (default), Bright Blue (active)
<div role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-label="Large circle indeterminate" class="progress-circle progress-indeterminate progress-lg"></div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-label="Circle indeterminate" class="progress-circle progress-indeterminate"></div>
<div role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-label="Small circle indeterminate" class="progress-circle progress-indeterminate progress-sm"></div>