Introduction
In LWC, lazy loading can be implemented using server-side Apex or client-side JavaScript. It can be combined with either HTML tables or Lightning Datatable components. This guide explores four approaches, their unique features, trade-offs, and high-level implementation strategies.
Unified Interaction Patterns: Scroll Bar vs. Load More Button
Before diving into implementation methods, let’s explore the two interaction patterns that drive lazy loading:
a) Scroll Bar (Infinite Scrolling)
- Seamless Experience: Automatically loads data as the user scrolls, eliminating manual actions.
- Real-Time Data Flow: Ideal for applications requiring continuous data updates (e.g., social feeds).
- Potential Drawbacks: Risk of over-fetching data and complex scroll position tracking.
b) Load More Button
- Explicit Control: Users decide when to load additional data, reducing unnecessary server calls.
- Predictable Performance: Simplifies error handling and resource management.
- Potential Drawbacks: Requires user interaction, which may disrupt browsing flow.
Regardless of the underlying method (server-side or client-side, HTML table or datatable), two common interaction patterns are used to trigger lazy loading:
We will see below 4 approaches and their sample LWC component to implement the lazy loading –
- Server-Side with HTML Table & Apex
- Server-Side with Lightning Data Table & Apex
- Client-Side with HTML Table & Apex
- Client-Side with Lightning Data Table & Apex
Pros and Cons Comparison
| Method | Pros | Cons |
|---|---|---|
| 1. Server + HTML Table | • Full control over UI design. • Scalable for large datasets. • Reduces client resource usage. | Manual DOM updates for new data. Increased server load due to frequent API calls. Requires Apex controllers for data fetching. |
| 2. Server + Lightning Data Table | Built-in features (sorting). Server-efficient for large data. Native Salesforce integration. | Limited UI customization (constrained by Salesforce LWC framework). Requires Apex controllers for data fetching. |
| 3. Client + HTML Table | Instant navigation after initial load. No post-load server calls. | Poor performance with large datasets. Long initial load time. Browser memory issues. |
| 4. Client + Lightning Data Table | Rich interactivity (client-side sorting/filtering). Pre-built UI components. | Client memory limitations for large data. No server-side filtering/sorting after initial load. |
🌐 Server Side Lazy Loading Techniques –
Note : We will be using Offset in Apex Class for Server Side Lazy Loading, which has a limit of 2000 records, please refer SFDC Documentation for the limits. For, more than 2000 records refer our another blog – Server Side OFFSET-Free Lazy Loading (Keyset Pagination) With Infinite Scroll In Salesforce LWC.
1. Server-Side Lazy Loading with HTML Table & Apex
Features –
- Data Source: Apex methods fetch paginated data using
OFFSETandLIMITSOQL clauses. - UI Component: Custom HTML table built with
<table>and LWC directives likefor:each. - Triggers:
- Scroll: Track scroll position via JavaScript to fetch the next chunk.
- Load More: Increment the page counter on button click.
- Use Case: Large datasets requiring server-side filtering and lightweight UI.
High-Level Implementation Approach
- Apex: Create a method with
@AuraEnabledto return paginated data using LIMIT andOFFSET. - LWC: Track page numbers and using imperative calls to fetch data.
- UI: Render rows dynamically in the HTML table. For scroll, calculate scroll position via javascript.
a) Example – Server Side Lazy Loading In HTML Table With Scroll Bar
This LWC example demonstrates lazy loading functionality in a HTML table using scroll bar. The component displays contact records. It fetches more data from the server as users scroll the table. The next set of records is appended in the table.
Demo –
High-Level Code Explanation
- HTML File
- Lightning Card: Wraps the table in a styled container with a title and icon.
- Scrollable Html Table: Displays contact data in a table with the following features:
- Sticky Header: Ensures the header remains visible during scrolling.
- Dynamic Data: Rows are populated using the
contactsproperty. - Serial Numbers: Adds a serial number column for each contact.
- Loading Spinner: Displays a spinner and a “Loading contacts…” message when the
isLoadingflag is true. - Load More on Scroll Bar:
- Visibility: Lazy load contacts based on page size. Displays “All contacts loaded” when no more records are available.
- Back to Top Button:
- Positioning: Placed at the bottom-right corner.
- Visibility: Controlled dynamically based on scroll position.
- Action: Smoothly scrolls the page to the top when clicked.
- JavaScript File
- Properties
contacts: Stores the list of contact records retrieved from the server.pageSize: Defines the number of records fetched per server call (default is 5).offset: Tracks the starting index for the next batch of records(default is 0).isLoading: Indicates whether a data-fetching operation is in progress.hasMoreRecords: Signals whether there are additional records to load.
- Methods
connectedCallback- Automatically called when the component is inserted into the DOM.
- Fetches the initial batch of contacts by invoking
loadInitialData.
loadInitialData- Fetches data from the server using the
getContactsApex method. - Appends new contacts to the
contactsarray - Updates the
offsetfor the next batch and toggles thehasMoreRecordsflag based on the server response. - Capture errors if the Apex call fails.
- Fetches data from the server using the
loadingDelay- Introduces a 1-second delay to mimic real-world API behavior and improve UX.
loadMoreData- Triggered By Scroll events or manual user action.
- Fetches the next batch of records by invoking
loadInitialData.
allLoaded- A getter to check if all records have been loaded.
- Returns
trueifhasMoreRecordsis false and there are loaded contacts.
processcontacts- Adds serial numbers to each contact for display.
- Uses the current length of
contactsto calculate the serial number.
handleScroll- Scroll Monitoring: Detects when the user scrolls near the bottom of the container and triggers
loadMoreData. - Back to Top Button Toggle: Displays or hides the button based on the scroll position.
- Scroll Monitoring: Detects when the user scrolls near the bottom of the container and triggers
scrollToTop- Scrolls the container to the top for better navigation.
setScrollableHeight- Calculates and sets the height of the scrollable container based on the number of visible rows.
- Properties
Sample Code –
b) Example – Server Side Lazy Loading In HTML Table With Load More Button
This LWC example demonstrates lazy loading functionality in a HTML table with a “Load More” button. The component displays contact records. It fetches more data from the server as users click on the “Load More” button. It appends the next set of records in the table.
- The LWC loads an initial set of contacts from the server using the
getContactsApex method. The number of records loaded is determined by thepageSizeproperty. - The LWC processes the loaded contacts by adding a serial number to each contact and then updates the tracked
contactsproperty to reflect the changes. - The LWC allows users to load additional contacts by clicking the “Load More” button. It uses the
offsetproperty to determine the starting point for the next set of records, ensuring that data is fetched efficiently from the server. - The LWC dynamically updates the scrollable container’s content by appending new rows while ensuring the scroll bar reflects the total number of loaded records.
- The LWC includes a “Back to Top” button that becomes visible when the user scrolls down. This button allows users to quickly scroll back to the top of the table for better navigation.
Demo –
Sample Code –
2. Server-Side Lazy Loading with Lightning Data table & Apex
Features –
- Data Source: Paginated data from Apex, similar to the HTML table approach.
- UI Component: Built-in
lightning-datatablewith sorting, styling, and column customization. - Triggers:
- Scroll: Use the
onloadmoreevent or custom scroll listeners. - Load More: Update the datatable’s
dataproperty on button click.
- Scroll: Use the
- Use Case: Applications needing a feature-rich table with server-managed data.
High-Level Implementation Approach
- Apex: Create a method with
@AuraEnabledto return paginated data using LIMIT andOFFSET. - LWC: Use
lightning-datatableand bind columns/data. For scroll, useonloadmoreor custom logic; for the button, update the Datatable’sdataproperty.
Below are key attributes and events in Lightning Datatable that enable lazy loading:
enable-infinite-loading:- Enables lazy loading.
- Loads more data when the user scrolls to the end of the table.
- Works with the
onloadmoreevent to fetch additional data.
load-more-offset:- Determines how close the user must scroll to the bottom to trigger loading.
- Default value:
20pixels from the bottom.
onloadmore:- Event handler that triggers when more data needs to be loaded.
- This is where the logic for fetching additional records is implemented.
a) Example – Server Side Lazy Loading In Lightning Data Table With Scroll Bar
This LWC example demonstrates lazy loading in a Lightning Datatable with scroll bar. The component displays account records in a scrollable table, fetching more data from the server as users scroll down.
Demo –
High-Level Code Explanation
This example demonstrates lazy loading in a Lightning Datatable. The component displays account records in a scrollable table, fetching more data from the server as users scroll down.
HTML File
- Lightning Card: Wraps the datatable in a styled container with a title and icon.
- Lightning Datatable: Displays the account data with the following features:
enable-infinite-loading: Enables lazy loading.onloadmore: Calls the JavaScript method to fetch additional records.hide-checkbox-columnandshow-row-number-column: Customize the appearance.
- Status Messages: Inform users whether data is loading or if all records are loaded.
JavaScript File
- Properties:
accounts: Stores account data.columns: Defines the table’s columns (e.g., Name, Rating).pageSize: Determines the number of records fetched per server call (default is 5).offset: Tracks the starting index for the next batch of records (default is 0).hasMoreRecords: Indicates if there are additional records to load.loadMoreStatusandisLoading: Track loading progress and display messages.
- Methods:
connectedCallback:- Invoked when the component is loaded.
- Fetches the initial set of account data by invoking the
loadDatamethod.
loadData:- Core method for fetching data using the Apex method
getAccounts. - Updates
accountswith new records and adjusts thehasMoreRecordsflag based on the server response. - Dynamically adjusts the height of the scrollable container to improve user experience.
- Core method for fetching data using the Apex method
loadMoreData:- Called when the user scrolls to the bottom of the table.
- Fetches the next set of records and appends them to
accounts.
allLoaded:- A getter that checks if all records have been loaded.
setScrollableHeight:- Dynamically sets the scrollable container’s height to fit the visible rows.
Sample Code –
b) Example – Server Side Lazy Loading In Lightning Data Table With Load More Button
This LWC example demonstrates lazy loading in a Lightning Datatable with a “Load More” button.. The component displays account records in a data table, fetching more data from the server as users click on load more buttom.
Demo –
High-Level Code Explanation
HTML File
- Lightning Card
Wraps the datatable in a styled container with a title and icon (standard:account). This provides a clean and visually appealing header for the component. - Lightning Datatable
Displays the account data with the following features:- Key Fields: Identifies records by their unique ID.
- hide-checkbox-column and show-row-number-column: Customizes the table appearance by removing checkboxes and adding row numbers.
- Dynamic Data: Data is dynamically populated via the
accountsproperty. - Columns: Defined using the
columnsproperty.
- Loading Spinner
Displays a spinner and a “Loading accounts…” message when theisLoadingflag is true. - Load More Button
Includes the following behaviors:- Visible When Applicable: Displays if more data can be loaded (
hasMoreRecordsis true). - Hides When All Data Loaded: Displays “All accounts loaded” when all data is fetched.
- Visible When Applicable: Displays if more data can be loaded (
- Back to Top Button
- Positioning: Placed at the bottom-right corner.
- Visibility: Becomes visible when the user scrolls down.
- Action: Smoothly scrolls the page to the top when clicked.
JavaScript File
- Properties
accounts: Tracks the account data displayed in the datatable.columns: Defines the table columns (e.g., “Account Name” and “Industry”).pageSize: Determines the number of records fetched per server call (default is 5).offset: Tracks the starting index for the next batch of records (default is 0).isLoading:Indicates whether a data-fetching operation is in progress.hasMoreRecords:Indicates if there are additional records to load.
- Methods
connectedCallback- Invoked when the component is loaded.
- Fetches the initial set of account data by invoking the
loadDatamethod.
loadData- Core method for fetching data using the Apex method
getAccounts. - Appends new records to the
accountsarray. - Updates the
offsetfor the next batch and toggles thehasMoreRecordsflag based on the server response. - Capture errors if the Apex call fails.
- Core method for fetching data using the Apex method
loadingDelay- Introduces a 1-second pause to mimic real-world API behavior and enhance UX.
handleLoadMore- Triggered By clicking the “Load More” button.
- Calls
loadDatato fetch the next batch of records.
handleScrollEvent- Adds an event listener to detect scroll activity.
- Displays or hides the scroll to top button based on the scroll position.
scrollToTop- Scrolls the page back to the top using a smooth animation.
allLoaded- A getter to determine if all records are loaded.
- Returns
trueif no more records are available (hasMoreRecordsis false) and some data has already been loaded.
Sample Code –
🖥️Client Side Lazy Loading Techniques –
1. Client-Side JavaScript with HTML Table
Features –
- Data Source: Entire dataset fetched initially, split into chunks using JavaScript.
- UI Component: Dynamic HTML table with client-side row rendering.
- Triggers:
- Scroll: Track scroll position to render the next chunk.
- Load More: Increment visible rows on button click.
- Use Case: Small datasets where client-side processing is acceptable.
High-Level Implementation Approach
- Data Fetching: Retrieve all data upfront and store it in a JavaScript array.
- Chunking: Slice data into segments using
Array.slice(). - UI: Render initial segment. For scroll, add event listeners to load the next chunk; for the button, increment the visible row count.
a) Example – Client Side Lazy Loading In HTML Data Table With Scroll Bar
This LWC example demonstrates lazy loading functionality in a HTML table using scroll bar. The component displays contact records. It fetches more data from the server as users scroll the table. The next set of records is appended in the table.
High-Level Code Explanation
- HTML File
- Lightning Card
Wraps the entire component in a styled container with the title “Client Side Lazy Loading In HTML Table With Scroll Bar – LWC” and thestandard:contactsicon. Provides a consistent Salesforce UI shell for the feature. - Scrollable Html Table: Displays contact data in a table with the following features:
- Sticky Header: Ensures the header remains visible during scrolling.
- Dynamic Data: Rows are populated using the contacts property.
- Serial Numbers: Adds a serial number column for each contact.
- Loading Spinner: Displays a spinner and a “Loading contacts…” message when the isLoading flag is true.
- Load More on Scroll Bar:
- Visibility: Lazy load contacts based on page size. Displays “All contacts loaded” when no more records are available.
- Back to Top Button:
- Positioning: Placed at the bottom-right corner.
- Visibility: Controlled dynamically based on scroll position.
- Lightning Card
- JavaScript File
- Properties
- contacts: Stores the list of contact records retrieved from the server.
- pageSize: Defines the number of records fetched per server call (default is 5).
- offset: Tracks the starting index for the next batch of records (default is 0).
- isLoading: Indicates whether a data-fetching operation is in progress.
- Methods
- connectedCallback
- Automatically called when the component is inserted into the DOM.
- Fetches the initial batch of contacts by invoking loadInitialData.
- loadInitialData
- Fetches data from the server using the getAllContacts Apex method.
- Processes and appends new contacts to the contacts array.
- Updates the offset for the next batch and toggles the hasMoreRecords flag based on the response.
- Captures and handles errors if the Apex call fails.
- loadingDelay
- Introduces a 1-second delay to mimic real-world API behavior and improve UX.
- loadMoreData
- Triggered by scroll events when nearing the bottom or by manual user action.
- Invokes loadInitialData to fetch the next batch of records.
- allLoaded
- A getter to check if all records have been loaded.
- Returns true if hasMoreRecords is false and there are loaded contacts.
- processContacts
- Adds serial numbers to each contact for display.
- Uses the current length of contacts to calculate the serial number.
- handleScroll
- Scroll Monitoring: Detects when the user scrolls near the bottom of the container and triggers loadMoreData.
- Back to Top Button Toggle: Displays or hides the button based on the scroll position.
- scrollToTop
- Scrolls the container to the top for better navigation.
- setScrollableHeight
- Calculates and sets the height of the scrollable container based on the number of visible rows.
- connectedCallback
- Properties
Sample Code –
2. Client-Side JavaScript with Lightning Datatable
Features –
- Data Source: Full dataset loaded upfront, paginated via JavaScript.
- UI Component:
lightning-datatablewith client-side data slicing. - Triggers:
- Scroll: Dynamically update the datatable’s bound data on scroll.
- Load More: Adjust the displayed dataset on button click.
- Use Case: Moderate datasets requiring datatable features and client-side flexibility.
High-Level Implementation Approach
- Data Handling: Load all data into the component and manage visibility via JS.
- Triggers: Update the Datatable’s bound
dataproperty dynamically. For scroll, calculate thresholds; for the button, adjust the displayed dataset.
To be continues , code sample for Client Side, will share in new blog 🙂
Choosing the Right Approach
- Prioritize server-side methods for large datasets or real-time data accuracy.
- Opt for client-side methods if initial load time isn’t critical and datasets are small.
- Use Datatable for standardized features, and HTML tables for custom designs.
Align your lazy loading strategy with your application’s data size. Consider UX goals and technical constraints. This way, you can strike the right balance between performance and usability.New chat


Leave a comment