Blog

Progress bar with Animation

Use case:

We have a particular milestone kept for each user in our organization and we need to inform them of their progress in an attractive and user-friendly way.

Solution:

A progress bar with milestone indicators can be a highly effective solution for such use cases. By incorporating backend functionality for each milestone or progress point, we can enhance the interactivity and functionality of the solution.

A basic one would look like below:

progress-bar

You can add more functionalities to this simple progress bar to make it user-friendly and attractive at the same time.

progress-bar

You can change the colors or add different functionalities at each checkpoint so that it would be easy for users to understand.

progress-bar

Let’s make it more interesting by adding an animation to the progress bar.

Video:

You would have noticed that one can also see the progress in percentage below. One could even add a toast or a completed email or any such functionalities at any milestone completed or reached.

Code Block:

progressBar.css:

.progress-width{
max-width: 95% !important;
min-width: 95% !important;
}


//Styles for the progress bar icons

.success-icon{
--sds-c-icon-color-foreground-default: #2e844a;
--sds-c-icon-color-background: #ffffff;
}
.default-icon,.choice-icon {
--sds-c-icon-color-foreground-default: #1ab9ff;
--sds-c-icon-color-background: #ffffff;
}
.error-icon {
--sds-c-icon-color-foreground-default:#ea001e;
--sds-c-icon-color-background: #ffffff;
}

progressBar.html:

<template>
<div class="slds-card slds-p-around_x-large">
<div class="slds-progress slds-p-around_none progress-width">
<!--Progrss bar icon setup-->
<ol class="slds-progress__list">
<template for:each={markerDetails} for:item="checkpoint">
<li class="" key={count}>
<button
class="slds-button slds-button_icon slds-progress__marker slds-progress__marker_icon"
title={checkpoint.iconName} data-name={checkpoint.iconName} >
<lightning-icon
icon-name="utility:choice"
size="small"
alternative-text={checkpoint.iconName}
class={checkpoint.iconClass}
data-name={checkpoint.iconName}
onclick={handleProgressBarSelection}>
</lightning-icon>
<span class="slds-assistive-text">{checkpoint.iconName}</span>
</button>
</li>
</template>
</ol>
<!--Progrss bar setup-->
<div class="slds-progress-bar slds-progress-bar_small" aria-valuemin="0" aria-valuemax="100"
aria-valuenow={currentDocPercentage} aria-label="Label" role="progressbar">
<span class="slds-progress-bar__value" style={singleDocPercentStyle}>
<span class="slds-assistive-text">Progress: {currentDocPercentage}</span>
</span>
</div>
</div>
<!--Message section-->
<div class="slds-align_absolute-center"><div class="slds-text-title_caps slds-p-vertical_medium">Percentage completed: {currentDocPercentage}%</div></div>
</div>
</template>

progressBar.js:

import { LightningElement } from 'lwc';

export default class ProgressBarLwc extends LightningElement {
currentDocPercentage = 0;
//Sets the value of the progress
singleDocPercentStyle = 'width:0%';

//Simple set up for the icon, this can be made dynamic
markerDetails = [
{ iconName: 'Checkpoint 1', iconClass: 'success-icon'},
{ iconName: 'Checkpoint 2', iconClass: 'choice-icon'},
{ iconName: 'Checkpoint 3', iconClass: 'error-icon'}
];

//onclick event that is fired on clicking the icons
handleProgressBarSelection(event){
this.currentDocPercentage = 0; //Initial width of the progress bar
this.singleDocPercentStyle = `width:${this.currentDocPercentage}%`;

//Animation setup
setTimeout(() => {
let intervalID = setInterval(() => {
//Set at 100% to stop the animation, needs to be modified as you need to work at different checkpoints
if (this.currentDocPercentage === 100) {
clearInterval(intervalID);
} else {
animate();
}
}, 30);//this sets the speed of the animation
}, 10);

const animate = () => {
//This increases the value of the progressbar and by using the animation we slow down the progress
this.currentDocPercentage++;
this.singleDocPercentStyle = `width:${this.currentDocPercentage}%`;
setTimeout(() => {
this.singleDocPercentStyle = `width:${this.currentDocPercentage}%`;
}, 10100);
};
}
}