Custom Progress Bar in Lightning

In this post, I will walk you through the implementation of the Custom Progress Bar in Lightning from scratch. There is a Progress Indicator provided by Salesforce in Lightning Components Library which you can check here. But sometimes it is not enough as per our business requirement and we need to build it from scratch which is exactly what we will do here. This component will be reusable and the developer would just need to put the multiple sections of Forms in the Content section and this component will take care of the rest to display the Form section for the current Step.

Progress Indicators are important when we want to display long Forms but in multiple steps. Follow the below steps to implement Custom Progress Indicator in Lightning:

  1. In the lightning component, use a div tag with CSS to create multiple Circles and another div tag to create the Lines between Circles to create the progress indicator.
  2. In Circle, we will display a Checkmark or step Number. Either one of these will be displayed based on user interaction.
  3. Create different sections to display content for each Step and make it dynamic using aura:if such that only the section of the current Step should be displayed.
  4. Create Buttons Cancel, Back, Next, Submit which will be displayed based on the current Step.
  5. Use the CSS to update the Active and Previous Step and other look and feel after button click.

Also Read:

Implementation

First, create a progress bar in Lightning component along with the Content section for Forms and Buttons to render the different Form sections. At a time, only one Form Content section will be displayed. This should be rendered based on the current Step.

Create the Next and Back buttons to navigate through all the Sections. These buttons are conditional as well based on the current Step. For example, the Next button won’t be available on the Last Step.

ProgIndicator.cmp

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" >
    
    <aura:attribute name="intLastStep" type="Integer" default="5" />
    <aura:attribute name="intCurrentStep" type="Integer" default="1" />
    
    <!-- Init handler -->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
    <br/>
    <lightning:card class="slds-p-around_xx-small custom-height" title="Custom Progress Indicator">
        <br/>
        
        <!-- Progress Indicator STARTS -->
        <div style="text-align:center">
            <div class="circle-parent">
                <span class="circle cicrle-top-padding" aura:id="circle1">
                    <aura:if isTrue="{!lessthanorequal(v.intCurrentStep, 1)}">
                        <div class="cicrle-top-padding-step">1</div>
                    	<aura:set attribute="else">
                        	<lightning:icon class="activeStep activeBackground" aura:id="check1" iconName="action:check" alternativeText="Completed" title="Completed" size="x-small"/>
                        </aura:set>
                    </aura:if>
                </span>
                <span class="stepLabel" aura:id="label1">Step 1</span>
            </div>
            <span class="line" aura:id="line1"></span>
            <div class="circle-parent">
                <span class="circle" aura:id="circle2">
                	<aura:if isTrue="{!lessthanorequal(v.intCurrentStep, 2)}">
                        <div class="cicrle-top-padding-step">2</div>
                    	<aura:set attribute="else">
                        	<lightning:icon class="activeStep activeBackground" aura:id="check1" iconName="action:check" alternativeText="Completed" title="Completed" size="x-small"/>
                        </aura:set>
                    </aura:if>
                </span>
                <span class="stepLabel" aura:id="label2">Step 2</span>
            </div>
            <span class="line" aura:id="line2"></span>
            <div class="circle-parent">
                <span class="circle" aura:id="circle3">
                	<aura:if isTrue="{!lessthanorequal(v.intCurrentStep, 3)}">
                        <div class="cicrle-top-padding-step">3</div>
                    	<aura:set attribute="else">
                        	<lightning:icon class="activeStep activeBackground" aura:id="check1" iconName="action:check" alternativeText="Completed" title="Completed" size="x-small"/>
                        </aura:set>
                    </aura:if>
                </span>
                <span class="stepLabel" aura:id="label3">Step 3</span>
            </div>
            <span class="line" aura:id="line3"></span>
            <div class="circle-parent">
                <span class="circle" aura:id="circle4">
                	<aura:if isTrue="{!lessthanorequal(v.intCurrentStep, 4)}">
                        <div class="cicrle-top-padding-step">4</div>
                    	<aura:set attribute="else">
                        	<lightning:icon class="activeStep activeBackground" aura:id="check1" iconName="action:check" alternativeText="Completed" title="Completed" size="x-small"/>
                        </aura:set>
                    </aura:if>
                </span>
                <span class="stepLabel" aura:id="label4">Step 4</span>
            </div>
            <span class="line" aura:id="line4"></span>
            <div class="circle-parent">
                <span class="circle" aura:id="circle5">
                	<aura:if isTrue="{!lessthanorequal(v.intCurrentStep, 5)}">
                        <div class="cicrle-top-padding-step">5</div>
                    	<aura:set attribute="else">
                        	<lightning:icon class="activeStep activeBackground" aura:id="check1" iconName="action:check" alternativeText="Completed" title="Completed" size="x-small"/>
                        </aura:set>
                    </aura:if>
                </span>
                <span class="stepLabel " aura:id="label5">Step 5</span>
            </div>
        </div>
        <!-- Progress Indicator ENDS -->
        
        <!-- Form Content of Steps STARTS -->
        <div class="slds-p-around_xx-large">
        	
            <!-- All your Forms should be insde these respective sections -->
            <aura:if isTrue="{!v.intCurrentStep == 1}">
                <p class="content slds-align_absolute-center">Form Content for Step 1</p>
            </aura:if>
            
            <aura:if isTrue="{!v.intCurrentStep == 2}">
                <p class="content slds-align_absolute-center">Form Content for Step 2</p>
            </aura:if>
            
            <aura:if isTrue="{!v.intCurrentStep == 3}">
                <p class="content slds-align_absolute-center">Form Content for Step 3</p>
            </aura:if>
            
            <aura:if isTrue="{!v.intCurrentStep == 4}">
                <p class="content slds-align_absolute-center">Form Content for Step 4</p>
            </aura:if>
            
            <aura:if isTrue="{!v.intCurrentStep == 5}">
                <p class="content slds-align_absolute-center">Form Content for Final Step</p>
            </aura:if>
            <!-- Form Contet of Steps ENDS -->
            
            <br/>
            <br/>
            
            <!-- Buttons STARTS -->
            <aura:if isTrue="{!v.intCurrentStep == 1}">
                <!-- Cancel Button -->
                <lightning:button label="Cancel" title="Neutral action" onclick="{! c.handleClick }"/>
            </aura:if>
            <aura:if isTrue="{!v.intCurrentStep != 1}">
                <!-- Back Button -->
            	<lightning:button label="Back" title="Neutral action" onclick="{! c.handleBack }"/>
            </aura:if>
            <aura:if isTrue="{!v.intCurrentStep != v.intLastStep}">
                <!-- Next Button -->
            	<lightning:button variant="brand" label="Next" title="Brand action" onclick="{! c.handleNext }" />
            </aura:if>
            <aura:if isTrue="{!v.intCurrentStep == v.intLastStep}">
                <!-- Submit Button -->
            	<lightning:button variant="brand" label="Submit" title="Brand action" onclick="{! c.handleClick }" />
            </aura:if>
            <!-- Buttons ENDS -->
            
        </div>
	</lightning:card>
    
</aura:component>

After the Next or Back button is clicked, the respective section will be displayed. And CSS will be updated in the controller and helper to update the CSS for current and previous steps.

ProgIndicatorController.js

({
	doInit : function(component, event, helper) {
        helper.doInitHelper(component, event, helper);
	},
    
    handleNext : function(component, event, helper) {
        var intCurrentStep = component.get('v.intCurrentStep');
		component.set('v.intCurrentStep', intCurrentStep + 1);
        helper.updateCss(component, event, helper);
	},
    
    handleBack : function(component, event, helper) {
        helper.updateCss(component, event, helper);
		component.set('v.intCurrentStep', component.get('v.intCurrentStep') - 1);
	}
})

ProgIndicatorHelper.js

({
    doInitHelper : function(component, event, helper) {
        
        // To make step 1 Active
		var circle = component.find('circle1');
        var label = component.find('label1');
        $A.util.toggleClass(circle, 'activeStep');
        $A.util.toggleClass(circle, 'activeBackground');
        $A.util.toggleClass(label, 'activeLabel');		
	},
    
	updateCss : function(component, event, helper) {
        
        // To toggle the CSS to make step Active/Deactive
        var intCurrentStep = component.get('v.intCurrentStep');
		var circle = component.find('circle' +intCurrentStep);
        var label = component.find('label' +intCurrentStep);
        var line = component.find('line' +(intCurrentStep-1));
        var check = component.find('check' +intCurrentStep);
        $A.util.toggleClass(circle, 'activeStep');
        $A.util.toggleClass(circle, 'activeBackground');
        $A.util.toggleClass(label, 'activeLabel');
        $A.util.toggleClass(line, 'activeBackground');
        $A.util.toggleClass(check, 'activeBackground');
        $A.util.toggleClass(check, 'activeStep');
	}
})

And finally, here is all the custom CSS that will do all the magic.

ProgIndicator.css

.THIS {
}
.THIS .custom-height{
    height: 500px;
}
.THIS .circle {
    height: 37px;
    width: 36px;
    border-radius: 50%;
    border: 2px solid #1b7a39;
    display: inline-block;
}
.THIS .cicrle-top-padding-step{
    padding-top: 5px;
}
.THIS .line {
    background-color: gray;
    height: 1px;
    width: 15%;
    display: inline-block;
    padding-bottom: 2px;
}
.THIS .circle-parent{
    width: 35px;
    display: inline-grid;
    white-space: nowrap;
}
.THIS .stepLabel{
    padding-top: 5px;
    color: gray;
}
.THIS .content{
    font-size: 25px;
}
.THIS .activeStep{
    color: White;
}
.THIS .activeLabel{
    color: #1b7a39;
}
.THIS .activeBackground{
    background-color: #1b7a39;
}
.THIS .activeLine{
    background-color: #1b7a39;
}

Custom Progress Indicator in Lightning

This is how it will look after this implementation:

Custom Progress Bar / Indicator in Lightning
Custom Progress Bar / Indicator in Lightning

This is how we can implement a Custom Progress Bar in Lightning. In case you don’t want to miss new posts, please Subscribe here.

You can check more such custom implementations in Lightning here.

See you next time. Thanks !

3 thoughts on “Custom Progress Bar in Lightning”

  1. Hi NiksDeveloper,

    Above topic is good and very helpful. I would like to add some changes for the same. For example if i would like to add different colors on different stages and wants to display those colors from backend logic. Let say if Increment –>Green color, if Decrement–>Red color for each stage.

    Your help will be appreciated. Let me know if any clarification needed.

    Reply
  2. Hi Niksdeveloper, I am looking for in place of circles, round buttons design including number and name in LWC progress bar. I hope u helpful to me

    Reply

Leave a Comment