Building a Custom Path in Lightning Web Components

Building a Custom Path in Lightning Web Components

Introduction:

A progress indicator component communicates to the user the progress of a particular process.

In this post, I am going to show you how to make your Salesforce app super user-friendly by creating a custom path using "lightning-progress-step".

Component Reference: Progress Step

Scenario :

While crafting a Lightning Web Component (LWC) for a user details form, I found it essential to include a form path. This feature helps organise user information based on categories, making data collection more straightforward. The form now guides users through different sections, ensuring I get the specific details needed for each category.

I have added "Next" and "Previous" buttons to navigate through the paths. I have added this component to the Account record page.

If you want to make your component more interactive you can use the SLDS guide for Progress Indicator.

PS: I have used random fields for demo purposes, please update as per requirement.

Sample Code :

UserForm.html
<template>
    <lightning-card>
        <lightning-progress-indicator current-step={selectedStep} type="path" variant="base">
            <template for:each={steps} for:item="step">
                <lightning-progress-step id={step.value} label={step.label} value={step.value} key={step.label}
                    onclick={stepSelectionHanler}></lightning-progress-step>
            </template>
        </lightning-progress-indicator>
    </lightning-card>

<template if:true={AccountRecord}>
        <!-- PERSONAL DETAILS SECTION -->
        <template lwc:if={showPersonalDetails}>
            <div class="pointerTableContainer2">
                <div class="section3" data-professional-skills>
                    <lightning-layout multiple-rows class="slds-theme_shade">
                        <lightning-layout-item padding="around-small" size="12">
                            <lightning-layout class="slds-box contentBox" multiple-rows>
                                <lightning-layout-item padding="around-small" size="4">
                                    <p>Personal</p>
                                </lightning-layout-item>
                                <lightning-layout-item padding="around-small" size="4">
                                    <lightning-input required type="text" variant="label-stacked" label="Name" name="Name"
                                        value={AccountRecord.Name} onchange={handleChange}></lightning-input>
                                </lightning-layout-item>
                            </lightning-layout>
                        </lightning-layout-item>
                    </lightning-layout>
                </div>

                <div class="footer">
                    <lightning-layout multiple-rows class="slds-theme_shade">
                        <lightning-layout-item size="12">
                            <lightning-layout multiple-rows>
                                <lightning-layout-item padding="around-small" size="6">
                                    <lightning-button variant="" label="Previous" title="Primary action"
                                        onclick={handlePreviousAction} class="slds-var-m-left_x-small"></lightning-button>
                                </lightning-layout-item>
                                <lightning-layout-item padding="around-small" size="6">
                                    <lightning-button variant="" label="Next" title="Primary action" onclick={handleNextAction}
                                        class="slds-var-m-left_x-small"></lightning-button>
                                </lightning-layout-item>
                            </lightning-layout>
                        </lightning-layout-item>
                    </lightning-layout>
                </div>

            </div>
        </template>
        <!-- PERSONAL DETAILS SECTION -->

        <!-- EDUCATION DETAILS SECTION -->
        <template lwc:if={showEducationDetails}>
            <div class="pointerTableContainer2">
                <div class="section3" data-strategic-impact>
                    <lightning-layout multiple-rows class="slds-theme_shade">
                        <lightning-layout-item padding="around-small" size="12">
                            <lightning-layout class="slds-box contentBox" multiple-rows>
                                <lightning-layout-item padding="around-small" size="4">
                                    <p>Industry</p>
                                </lightning-layout-item>
                                <lightning-layout-item padding="around-small" size="4">
                                    <lightning-input required type="text" variant="label-stacked"
                                        label="Education Catagory" name="Industry" value={AccountRecord.Industry}
                                        onchange={handleChange}></lightning-input>
                                </lightning-layout-item>
                            </lightning-layout>
                        </lightning-layout-item>
                    </lightning-layout>
                </div>

                <div class="footer">
                    <lightning-layout multiple-rows class="slds-theme_shade">
                        <lightning-layout-item size="12">
                            <lightning-layout multiple-rows>
                                <lightning-layout-item padding="around-small" size="6">
                                    <lightning-button variant="" label="Previous" title="Primary action"
                                        onclick={handlePreviousAction} class="slds-var-m-left_x-small"></lightning-button>
                                </lightning-layout-item>
                                <lightning-layout-item padding="around-small" size="6">
                                    <lightning-button variant="" label="Next" title="Primary action" onclick={handleNextAction}
                                        class="slds-var-m-left_x-small"></lightning-button>
                                </lightning-layout-item>
                            </lightning-layout>
                        </lightning-layout-item>
                    </lightning-layout>
                </div>

            </div>
        </template>
        <!-- EDUCATION DETAILS SECTION -->

        <!-- PROFESSIONAL DETAILS SECTION -->
        <template lwc:if={showProfessionalDetails}>
            <div class="pointerTableContainer2">

                <div class="section3" data-goals-results>
                    <lightning-layout multiple-rows class="slds-theme_shade">
                        <lightning-layout-item padding="around-small" size="12">
                            <lightning-layout class="slds-box contentBox" multiple-rows>
                                <lightning-layout-item padding="around-small" size="4">
                                    <p>Compensation</p>
                                </lightning-layout-item>
                                <lightning-layout-item padding="around-small" size="4">
                                    <lightning-input required type="number" variant="label-stacked"
                                        label="Annual Revenue" name="AnnualRevenue"
                                        value={AccountRecord.AnnualRevenue}
                                        onchange={handleChange}></lightning-input>
                                </lightning-layout-item>
                            </lightning-layout>
                        </lightning-layout-item>
                    </lightning-layout>
                </div>

                <div class="footer">
                    <lightning-layout multiple-rows class="slds-theme_shade">
                        <lightning-layout-item size="12">
                            <lightning-layout multiple-rows>
                                <lightning-layout-item padding="around-small" size="6">
                                    <lightning-button variant="" label="Previous" title="Primary action"
                                        onclick={handlePreviousAction} class="slds-var-m-left_x-small"></lightning-button>
                                </lightning-layout-item>
                                <lightning-layout-item padding="around-small" size="6">
                                    <lightning-button variant="" label="Next" title="Primary action" onclick={handleNextAction}
                                        class="slds-var-m-left_x-small"></lightning-button>
                                </lightning-layout-item>
                            </lightning-layout>
                        </lightning-layout-item>
                    </lightning-layout>
                </div>

            </div>
        </template>
        <!-- PROFESSIONAL DETAILS SECTION -->
    </template>

    <template if:false={AccountRecord}>
        <div>
            <p>Sorry Unable to find Account Details</p>
        </div>
    </template>

</template>
UserForm.js
import { LightningElement, api, wire, track } from 'lwc';
//Apex Methods
import fetchAccountRecords from '@salesforce/apex/AccountController.getAccountRecordById';

//other imports
import { NavigationMixin } from 'lightning/navigation';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '@salesforce/apex';
export default class UserForm extends NavigationMixin(LightningElement) {
    @api recordId;
    error;
    @track AccountRecord;
    @track wiredAccountRecordResult;

    @track selectedStep = 'personalDetails';
    showPersonalDetails = true;
    showEducationDetails = false;
    showProfessionalDetails = false;

    steps = [
        { label: 'PERSONAL DETAILS', value: 'personalDetails' },
        { label: 'EDUCATION DETAILS', value: 'educationDetails' },
        { label: 'PROFESSIONAL DETAILS', value: 'professionalDetails' }
    ];

    connectedCallback() {
        console.log('RECORD ID :' + this.recordId);
    }

    stepSelectionHanler(event) {
        const step = event.target.value;
        this.selectedStep = step;
        // Map each step to its corresponding visibility property
        const stepToVisibility = {
            'personalDetails': 'showPersonalDetails',
            'educationDetails': 'showEducationDetails',
            'professionalDetails': 'showProfessionalDetails'
        };
        // Set visibility based on the selected step
        Object.keys(stepToVisibility).forEach(key => {
            this[stepToVisibility[key]] = key === step;
        });
    }

    //Fetch Account Record details dynamically by fetching the recordId and assign it to AccountRecord Obj.
    @wire(fetchAccountRecords, { recordId: "$recordId" })
    wiredAccRecords(value) {
        this.wiredAccountRecordResult = value;
        const { data, error } = value;
        if (data) {
            console.log("wiredAccountRecordResult DATA :: " + JSON.stringify(data));
            this.AccountRecord = data;
            console.log("AccountRecord DATA :: " + JSON.stringify(this.AccountRecord.Industry));
            this.error = undefined;
        } else if (error) {
            console.log("IF ERROR :: " + JSON.stringify(error));
            this.error = error;
            this.AccountRecord = undefined;
        }
    }

    //Previous button function to Show/Hide the sections based on the Current Step
    handlePreviousAction() {
        console.log('handlePreviousAction ' + this.selectedStep);
        this.showPersonalDetails = false;
        this.showEducationDetails = false;
        this.showProfessionalDetails = false;

        // Set the specific show property to true based on the selected step
        switch (this.selectedStep) {
            case 'educationDetails':
                this.showPersonalDetails = true;
                this.selectedStep = 'personalDetails';
                break;
            case 'professionalDetails':
                this.showEducationDetails = true;
                this.selectedStep = 'educationDetails';
                break;
            case 'personalDetails':
                this.showPersonalDetails = true;
                this.selectedStep = 'personalDetails';
                break;
        }
    }

    //Next button function to Show/Hide the sections based on the Current Step
    handleNextAction() {
        this.showPersonalDetails = false;
        this.professionalDetails = false;
        this.showEducationDetails = false;

        var currentStep = this.selectedStep;
        switch (currentStep) {
            case 'personalDetails':
                this.showEducationDetails = true;
                this.selectedStep = 'educationDetails';
                break;
            case 'educationDetails':
                this.showProfessionalDetails = true;
                this.selectedStep = 'professionalDetails';
                break;
            case 'professionalDetails':
                this.showProfessionalDetails = true;
                break;
        }
    }

}
UserForm.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightningCommunity__Page</target>
    </targets>
</LightningComponentBundle>

Summary :

Thanks for reading, I hope you find this article helpful. If you still have some doubts, comment down below ill try my best to answer your query.

If you want you can connect with me on my below social handles.

LinkedIn : Shubham Maske

Twitter : Shubham Maske