subscribe our youtube channel popup

How to use Lightning spinner in LWC

The loading indicator is an important part of the user interface of any web application. They tell users that an action is in progress and prevents confusion or repeated clicks. In terms of salesforce lightning web components (LWC), <Lightning-Spinner> Better that will make data or provide proper visuals during any long running operation. Join us to learn about How to use Lightning spinner in LWC.

This blog post shows how to build a simple LWC:

  1. Displays a Load Accounts button by default
  2. Click on the button that will shows a spinner
  3. Get 10 account records from a top controller
  4. Ensures that the spinner appears for a certain minimum period
  5. Renders the records in a Lightning Datatable

All this can be applied within 15 minutes and requires only three files: a top class, a LWC HTML template, and LWC JavaScript controller. Let’s dive.

What is a Spinner?

A spinner is a visual indicator used to show that a process or operation is in progress. This is especially helpful during slow or asynchronous operations such as:

  • Loading data from the server
  • Performing long-running Apex methods
  • Waiting for file uploads or downloads
  • Saving records or submitting forms

Spinners help prevent confusion and reduce the risk of users clicking buttons multiple times out of impatience. They act as a fine way of saying, “Please wait while your request is being processed.”

Learn about lazy loading in LWC.

Types of Spinners in Salesforce

Salesforce provides a built-in base component for spinners:

<lightning-spinner></lightning-spinner>

It supports several attributes:

  • size: Controls the spinner size (small, medium, large)
  • alternative-text: Provides screen readers with a description
  • variant: Can be brand, inverse, or neutral

Examples

<lightning-spinner size="small" alternative-text="Loading small..." />
<lightning-spinner size="large" variant="brand" alternative-text="Processing..." />

By default, these spinners are circular and simple, but they’re very effective for most cases.

Apex Controller: Retrieving Account Records

First, create an Apex class named AccountController. This class exposes a single method, getAccounts(), which returns the 10 most recently created Account records.

public with sharing class AccountController {
    @AuraEnabled(cacheable=true)
    public static List<Account> getAccounts() {
        // return 10 Accounts (adjust fields as needed)
        return [
            SELECT Id, Name, Industry, Phone
            FROM Account
            ORDER BY CreatedDate DESC
            LIMIT 10
        ];
    }
}

Key points:

  • @AuraEnabled(cacheable=true): It will allow us the method to be called from LWC and enables client-side caching for better performance.
  • LIMIT 10: Restricts the query to the latest 10 records.
  • ORDER BY CreatedDate DESC: Ensures the newest records are returned first.

Deploy this class to your org before moving on to the LWC.

HTML Template: Structuring the UI

The HTML template uses conditional rendering (if:true and if:false) to control when each element is displayed:

<template>
    <!-- If loading, show spinner -->
    <template if:true={isLoading}>
      <lightning-spinner alternative-text="Loading accounts" size="medium"></lightning-spinner>
    </template>
 
    <!-- If not loading and we have data, show table -->
    <template if:false={isLoading}>
      <template if:true={accounts.length}>
        <lightning-datatable
          key-field="Id"
          data={accounts}
          columns={columns}>
        </lightning-datatable>
      </template>
 
      <!-- Otherwise, show the Load button -->
      <template if:false={accounts.length}>
        <lightning-button
          label="Load Accounts"
          onclick={handleLoad}
          variant="brand">
        </lightning-button>
      </template>
    </template>
  </template> 

Template Breakdown

  1. Spinner Block
    <template if:true={isLoading}>…</template>: Renders only when isLoading is true.
  2. Content Block
    <template if:false={isLoading}>…</template>: Renders when isLoading is false.
  3. Datatable vs. Button
    • If accounts.length > 0, the datatable is displayed.
    • If no data exists yet, the Load Accounts button appears.

This approach will make sure that only one of these three elements (spinner, button, or table) is visible at any time.

JavaScript Controller: Managing State and Timing

In the JavaScript file, state variables and the data-fetch logic are defined:

import { LightningElement, track } from 'lwc';
import getAccounts from '@salesforce/apex/AccountController.getAccounts';

export default class AccountTableWithSpinner extends LightningElement {
  @track isLoading = false;
  @track accounts = [];

  columns = [
    { label: 'Name',     fieldName: 'Name'     },
    { label: 'Industry', fieldName: 'Industry' },
    { label: 'Phone',    fieldName: 'Phone'    }
  ];

  handleLoad() {
    this.isLoading = true;
    const spinnerMinTime = 13000; // min spinner duration in ms
    const startTime = Date.now();

    getAccounts()
      .then(data => {
        this.accounts = data;
      })
      .catch(error => {
        console.error('Error fetching accounts', error);
        // optionally show toast
      })
      .finally(() => {
        const elapsed = Date.now() - startTime;
        const remaining = spinnerMinTime - elapsed;
        // if data returned quickly, wait the remaining time
        setTimeout(() => {
          this.isLoading = false;
        }, remaining > 0 ? remaining : 0);
      });
  }
}
  • @track isLoading & accounts
    1. isLoading (boolean): Controls spinner visibility
    2. accounts (array): Holds the retrieved Account records
  • Columns: This will defines the columns for the Lightning Datatable
  • handleLoad():
    1. We will set isLoading = true to trigger the spinner.
    2. Let’s record the start time.
    3. Calls getAccounts() imperatively.
    4. Assigns returned data to accounts.
    5. In finally(), computes elapsed time and enforces the minimum spinner duration before hiding it.

Using an imperative call instead of @wire provides fine-grained control over when data is fetched and when the spinner appears or disappears.

Meta Configuration: Exposing the Component

Finally, ensure the component is exposed so it can be added to Lightning pages:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>63.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Place this file in the same folder as your HTML and JS files under force-app/main/default/lwc/accountTableWithSpinner.

Deploy & Test

  1. Deploy the Apex class and LWC bundle to your org via SFDX or the Developer Console.
  2. Now we will Open the Lightning App Builder then add our component to Home Page or Record Page.
  3. Add the AccountTableWithSpinner component to our required page.
  4. Let’s Save, Activate and Preview it if development is working fine or not.

Upon loading the page, only the Load Accounts button is visible. Once we click on it will display the spinner for at least 13 seconds, after that it will show Lightning Datatable with the 10 Account records.

Below is the screenshot before clicking on button and displaying spinner:

Below is the screenshot post clicking on button and displaying spinner it will better user experience and we will be able to add some text as well as the accounts are loading based on user requirement:

Now accounts are displayed post wait of 13 seconds as specified in our code:

Potential Extensions

This simple scenario can be extended in various ways:

  • Real-world Data: Replace the static Apex query with a SOQL query that filters based on user input (e.g., Account Type or Industry).
  • Dynamic Timing: Use a shorter minimum spinner time or remove it altogether once familiar with business requirements.
  • Custom Overlay: Wrap the spinner in a semi-transparent overlay to prevent clicks on the page while loading.
  • Error Toast: Dispatch a ShowToastEvent in the catch block so that it will notify users of errors.
  • Pagination: Add Next or Previous buttons to the page for large data sets.

Each of these enhancements builds on the same core principles: control the loading state, fetch data imperatively, and render results conditionally.

Conclusion

Developing and building a proper and user-friendly user interface in LWC is easy and straightforward when combining conditional rendering, the <lightning-spinner> component and imperative Apex calls. This blog shows how to develop a button-triggered data fetch that will make sure that users always see a loading spinner for a required duration before displaying results for better user interface.

By using the spinner duration, query logic and UI structure, these ways will serve as the foundation for more complex data loading scenarios in Salesforce. Whether fetching records, calling integrations or uploading files, providing clear feedback with a loading spinner enhances the end-user experience and reduces doubt during wait times.

Feel free to build upon this example, tailor it to your use cases and integrate it into larger Lightning pages. Happy coding:)

Satyam parasa
Satyam parasa

Satyam Parasa is a Salesforce and Mobile application developer. Passionate about learning new technologies, he is the founder of Flutterant.com, where he shares his knowledge and insights.

Articles: 45

Leave a Reply

Your email address will not be published. Required fields are marked *