Performance is one of the most critical success factors for modern Salesforce applications, especially Experience Cloud sites, LWR-based SPAs, and component-heavy Lightning apps. Users today expect fast page loads, instant interactions, and smooth navigation. Even a slight delay can impact user adoption and satisfaction. This is where Lazy Loading in Lightning Web Components (LWC) becomes a powerful performance optimization technique.
This blog will cover the top 5 lazy loading techniques you need for developing faster Lightning Web Components.
What is Lazy Loading in LWC?
Lazy loading means loading components, data, or resources only when they are actually needed, instead of loading everything up front during the initial page render.
In a traditional (eager-loaded) LWC approach:
- All child components
- All Apex calls
- All static resources
are initialized at once, even if the user never interacts with most of them.
In contrast, lazy loading ensures:
- Components load on demand
- Data is fetched only when required
- JavaScript execution is deferred until interaction
This dramatically reduces:
- Initial page load time
- JavaScript parsing and execution cost
- Network payload size
Let us see all the lazy loading techniques that can be used in Salesforce LWC.
1. Conditional Rendering—The Foundation of All Lazy Loading
In many cases, developers preload components that are intended to be used only in certain conditions or scenarios, without evaluating their performance impact. Even when not immediately required, these components trigger lifecycle events, make Apex calls, and may download JavaScript resources, ultimately slowing down overall LWC performance.
We should never render a component if we can’t see it on the user interface.
<template>
<template if:true={showDetails}>
<c-heavy-details></c-heavy-details>
</template>
</template>
showDetails = false;
handleClick() {
this.showDetails = true;
}
In the above example, Salesforce only loads c-heavy-details when showDetails evaluates to true. At that point, the component is downloaded and initialized.
2. Event-Driven Lazy Loading—Load Only After User Intent
Event-driven lazy loading is a design pattern where user actions act as the trigger for loading functionality. Instead of initializing everything during the initial render phase, the application waits for an event such as
- Button click
- Tab selection
- Accordion expansion
- Hover or focus event
- Scroll-to-section interaction
Only when the event occurs does the LWC:
- Render the required child component
- Execute Apex calls
- Import JavaScript utilities
- Fetch data or metadata
This ensures that no CPU cycles, network calls, or memory are wasted on features the user may never use.
2.1 Button-Based Lazy Loading
<lightning-button label="View Details" onclick={handleOpen}></lightning-button>
<template if:true={open}>
<c-details-panel></c-details-panel>
</template>
open = false;
handleOpen() {
this.open = true;
}
c-details-panel will only show when the user clicks the View Details button.
2.2 Modal Lazy Loading
The model component should also render when it is required, as it can contain validation logic, Apex calls, etc.
<template if:true={showModal}>
<c-edit-record-modal onclose={handleClose}></c-edit-record-modal>
</template>
showModal = false;
openModal() {
this.showModal = true;
}
handleClose() {
this.showModal = false;
}
The component edit-record-modal will only show when showModal is true.
2.3 Accordion-Based Lazy Loading—Load on Expansion
All accordion sections load at once—even collapsed ones. We should avoid it until it is expanded.
<lightning-accordion onsectiontoggle={handleToggle}>
<lightning-accordion-section name="details" label="Details">
<template if:true={loadDetails}>
<c-details></c-details>
</template>
</lightning-accordion-section>
</lightning-accordion>
loadDetails = false;
handleToggle(event) {
if (event.detail.openSections.includes('details')) {
this.loadDetails = true;
}
}
In the above example, the accordion will load and render when the section is toggled.
2.4 Tab-Based Lazy Loading
We use tabs to display different categories or types of data. By default, all components will render on page load itself.
<lightning-tabset onactive={handleTab}>
<lightning-tab label="Overview"></lightning-tab>
<lightning-tab label="History" value="history">
<template if:true={loadHistory}>
<c-history></c-history>
</template>
</lightning-tab>
</lightning-tabset>
loadHistory = false;
handleTab(event) {
if (event.target.value === 'history') {
this.loadHistory = true;
}
}
We can render heavy components when a specific tab is clicked.
3. Lazy Loading Apex Calls
Developers mostly call the Apex code in connectedCallback.
connectedCallback() {
this.loadPatientData();
this.loadProviderData();
}
This will call the loadPatientData and loadProviderData methods even if the component is hidden or the user navigates away. It might be called multiple times as well. We should avoid this anti-pattern.
hasLoaded = false;
renderedCallback() {
if (this.hasLoaded) return;
this.hasLoaded = true;
this.loadPatientData();
this.loadProviderData();
}
This pattern will reduce duplicate calls, reduce server load, and improve speed.
4. Component Splitting (Architectural Lazy Loading)
We should divide the big components into smaller components and use lazy loading for specific components while loading. If we use a big component, it will render the complete code at once. It delays component loading.
<c-dashboard></c-dashboard>
A better approach with smaller components and lazy loading. The report component will only render when loadReports is true.
<c-dashboard>
<c-metrics></c-metrics>
<template if:true={loadReports}>
<c-reports></c-reports>
</template>
</c-dashboard>
Smaller components are easier to test, and they have a specific responsibility.
5. Progressive Rendering (Partial Load)
We might need to show tabular data on the component. When an LWC receives a large dataset, rendering every record at once can quickly degrade performance:
- Slower initial page load
- Heavy DOM creation
- Increased JavaScript execution time
- Poor scrolling and interaction experience
Progressive Rendering (Partial Load) solves this problem by breaking rendering into small, controlled chunks.
<template for:each={visibleRecords} for:item="rec">
<c-record-row
key={rec.Id}
record={rec}>
</c-record-row>
</template>
pageSize = 20;
visibleRecords = [];
connectedCallback() {
this.visibleRecords = this.records.slice(0, this.pageSize);
}
loadMore() {
this.pageSize += 20;
this.visibleRecords = this.records.slice(0, this.pageSize);
}
In this component,
- Only 20 rows render initially.
- DOM grows incrementally
- Faster initial paint
- Better scrolling performance
This is called lazy loading by volume.
Anti-Pattern: Avoid CSS-Based Hiding
One of the most common performance pitfalls in Lightning Web Components is confusing visual hiding with lazy loading.
In many Salesforce implementations, components are hidden using CSS (display: none, visibility: hidden) with the assumption that hidden components do not impact performance. While this may be true from a visual perspective, it is not true from a runtime or execution perspective.
In LWC, a component that exists in the DOM—hidden or visible—has already:
- Been instantiated
- Executed its lifecycle hooks
- Initialized wire services
- Potentially executed Apex calls
This means the performance cost has already been paid, even if the user never sees or interacts with the component.
//html
<c-heavy-component class="hidden"></c-heavy-component>
//css
.hidden {
display: none;
}
A better approach for the above anti-pattern
<template if:true={showComponent}>
<c-heavy-component></c-heavy-component>
</template>
heavyComponent will only load when showComponent is true.
Summary
Lazy loading in Lightning Web Components loads a component when it is actually rendered into the DOM. By using these patterns, such as conditional rendering, event-driven loading, modal and section-based loading, and deferred Apex calls, developers can significantly reduce initial load time, avoid unnecessary processing, and create faster, more responsive Lightning applications.
References
Use Progressive Disclosure and Conditional Rendering
Related Posts
- Enhancing Performance with File Compression in Apex
- Enhance Apex Performance with Platform Caching
- How to Develop a Custom Record Picker for Salesforce LWR Sites
- The Hidden Risks of Overusing Lookups in Salesforce
- Top Mistakes Developers Make in Salesforce Apex Triggers
- How to Convert Text to Speech in Lightning Web Component
- Building a Dynamic Tree Grid in Lightning Web Component
- How to Build a Generic Modal Window in Lightning Web Component
- How to Integrate Google reCaptcha v3 into the Salesforce Experience Site
- Ultimate Guide to URL Accessibility in LWC
- How to Use Image Cropper in Salesforce Lightning Web Component
- Configurable Record Picker in Lightning Web Component
- Displaying Tabular Data with GraphQL in Lightning Web Component
