What is lazy loading in LWC and how do you implement it?

Understanding lazy loading in LWC

Lazy loading in Lightning Web Components (LWC) is the practice of deferring the loading of resources—components, data, images, or third-party libraries—until they are actually needed. The goal is to improve initial page performance, reduce bundle size, and provide a faster, more responsive user experience on Salesforce pages.

Why use lazy loading?

Benefits include reduced initial load time, lower memory usage, fewer server/API calls at startup, and improved perceived performance for end users. It’s especially useful for heavy components, large datasets, third-party libraries, and images.

Common lazy-loading techniques in LWC

Below are practical patterns you can use in LWC projects.

1) Render components on demand (conditional rendering)

Use conditional templates to avoid creating a heavy child component until needed (for example, on tab activation or user click).

// parentComponent.html

// parentComponent.js
import { LightningElement, track } from 'lwc';
export default class ParentComponent extends LightningElement {
@track showChild = false;
data = null;

handleShow() {
this.showChild = true; // child element is created only now
}
}

2) Lazy-load data using IntersectionObserver (load when visible)

Use IntersectionObserver to fetch data when a placeholder or anchor enters the viewport. This is useful for content below the fold or in long lists.

// lazyLoader.html

// lazyLoader.js
import { LightningElement, track } from 'lwc';
import getItems from '@salesforce/apex/MyController.getItems';

export default class LazyLoader extends LightningElement {
@track loaded = false;
@track items = [];
observer;

connectedCallback() {
// can also initialize observer in renderedCallback with a guard
}

renderedCallback() {
if (this.observer) {
return;
}
const options = { root: null, rootMargin: '0px', threshold: 0.1 };
this.observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !this.loaded) {
this.loaded = true;
this._loadData();
this.observer.disconnect();
}
});
}, options);

const anchor = this.template.querySelector('.anchor');
if (anchor) {
this.observer.observe(anchor);
}
}

async _loadData() {
try {
this.items = await getItems();
} catch (error) {
// handle error
}
}
}

3) Lazy-load third-party libraries and static resources

Use lightning/platformResourceLoader’s loadScript and loadStyle to load resources only when needed (e.g., when a chart or editor is shown).

import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import LIB from '@salesforce/resourceUrl/myLib';

connectedCallback() {
// Defer loading until user opens the widget
}

async loadLibIfNeeded() {
if (!this.libLoaded) {
try {
await loadScript(this, LIB + '/lib.min.js');
await loadStyle(this, LIB + '/lib.css');
this.libLoaded = true;
// initialize library
} catch (error) {
// handle
}
}
}

4) Lazy-load images

Use native browser lazy loading (loading="lazy") for images, or switch the src only when in view using IntersectionObserver to save bandwidth.

<img src="/path/to/image.jpg" loading="lazy" alt="..." />

5) Lazy-load on tab/change events or lightning-tabset

Delay data loading until tabs are activated (listen to tab activation events) to avoid fetching everything at once.

Best practices and caveats

  • Prefer data-first lazy loading: avoid rendering heavy DOM until data is available.
  • Use IntersectionObserver instead of scroll listeners for better performance and lower CPU usage.
  • Keep accessibility in mind — ensure screen readers can still access content or provide fallback actions.
  • When lazy-loading scripts, account for race conditions; show loading UI and fail gracefully.
  • Test across browsers and Salesforce mobile app — IntersectionObserver is well supported but validate your target audiences.
  • Avoid over-lazy-loading small, critical pieces — measure and prioritize the biggest wins first.

Summary

Lazy loading in LWC is about deferring work—component instantiation, data fetches, and resource loads—until they are required. Use conditional templates, IntersectionObserver, loadScript/loadStyle, tab-based triggers, and native browser features like loading="lazy" for images to dramatically improve initial load performance and user experience in Salesforce apps.