LWC Pagination
| |

Effortless LWC Pagination Example for Salesforce Trailblazers: A Simple and Reusable Component

Pagination Example
Pagination Example

Pagination is a way to divide a large list of items into smaller, easier-to-manage pages. It helps users navigate through content more efficiently by displaying a limited number of items per page. In Lightning Web Components, pagination can organize data for better performance and user experience.

Who is this article for?

The example I provide is easily implementable by any Salesforce professional, regardless of their role. Whether you’re an admin, business analyst (BA), quality assurance (QA) tester, or any other Salesforce stakeholder, you can quickly test or implement the pagination.

It also can be easily understood by non-Salesforce developers because the basic idea is the same for everyone.

In just 10 minutes, you’ll be able to demonstrate the outcome to the customer, while quickly adjusting the desired number of buttons.

Overview of the provided Pagination Component example


A short overview of what we will be discussing in this blog post:

1. Purpose: The Pagination Component demonstrates how to implement pagination in Lightning Web Components (LWC) for managing large datasets efficiently.

2. Structure:

– Template: Visual layout defined using SLDS elements, including navigation buttons and dynamically generated page number buttons.

– JavaScript Files: Logic for pagination functionality, including methods for navigation actions and dynamic page number generation.

3. Key Features:

– Dynamic Page Number Display: Generates page number buttons based on total pages and current page.

– Reusability: Designed for easy integration into various LWC projects, adaptable to different datasets.

– Efficient Navigation: Provides buttons for first, previous, next, and last pages for streamlined dataset navigation.

4. Implementation:

– Integration guidance for managing pagination of datasets like Accounts and Leads or every custom object that can be easily implemented by any Salesforce professional.

– Configuration options for record sizes and total record counts for flexibility.

We will cover a straightforward solution for implementing pagination in LWC applications, enhancing usability and performance with efficient dataset navigation.

Importance of pagination in web development

Pagination is crucial in web development because it significantly improves the usability and loading time of websites. By breaking down content into smaller, more manageable sections, users can find information faster, reducing the overwhelming effect of loading a massive amount of data at once.

For developers, implementing pagination means better website performance and enhanced user satisfaction, as it aligns with how users prefer to consume content: bit by bit, rather than all at once.

Create PaginationController apex class

Before proceeding, let’s be on the same page in case you don’t have Visual Studio Code installed or set, and will add Lightning Studio Free Chrome Extension so that we can easily create and deploy our component.

We’ll create a PaginationController Apex class that will be responsible for retrieving the necessary accounts to display on the page, with 5 accounts per page.

Open your org then go to Lightning Studio extension -> click on New Component to create the PaginationController apex class -> giving the name as PaginationController.

Copy the bellow code from PaginationController.cls and replace it in the Lightning Studio PaginationController apex class.

PaginationController.cls
PaginationController.cls
public class PaginationController {
 @AuraEnabled(cacheable=true)
    public static Account[] getAccountList(){
        return [SELECT Id, Name FROM Account];
    }
}
PaginationController.cls

As seen here, we’re selecting the records we intend to display on the page. You can opt for any object you require; for now, we’ll proceed with accounts.
Adding @AuraEnabled(cacheable=true) to our method enables it to be imported into the next JavaScript file, where we’ll actually expose them on the page.

Setting Up the Child Pagination Component

We won’t dive into the technical details of how the LWC Pagination Component works or what each method does. Instead, you’ll simply copy and paste it where needed. Then, I’ll walk you through any additional configurations required to customize it for your needs.

Now we will create a pagination LWC Component using Lightning Studio

Create child pagination LWC Component

From Lightning Studio extension -> click on New Component and Create New Component then set the following fields:

  • name - pagination
  • isExposed - true
  • Targets: for now don’t choose anything, this will not be directly exposed, instead it will be used in a parent component for which we want to implement the pagination logic.

Click Deploy

Preparing pagination.js file

Replace the existing code of Lightining Studio pagination.js by Pasting the bellow code from pagination.js -> Save -> then Deploy

pagination.js
pagination.js
import { LightningElement, api} from 'lwc';

export default class Pagination extends LightningElement {
    currentPage = 1;
    totalRecords
    totalPageNumbers = 5
    pageNumbers = [];
    disabledPageNumbers = [];
    //nrPagesLeft is used to see how pages are left when we are on current page
    nrPagesLeft = 0;
    //when using @api we make the variable global
    @api recordSize = 5 //records per page
    totalPage = 0
    get records(){
        return this.visibleRecords;
    }

    @api records
    //data comming via records param from parent component paginationDemo.html
    set records(data){
        if(data){
            this.totalRecords = data 
            this.recordSize = Number(this.recordSize);
            //Math.ceil() round up 1.3 = 2 or 1.7 is consiered as 2
            //totalPage = total number of pages
            this.totalPage = Math.ceil(data.length / this.recordSize);
        
            this.updateRecords();
        }
    }

    nextHandler(){
        if(this.currentPage < this.totalPage){
            this.currentPage = this.currentPage + 1;
            this.updateRecords();
        }
    }

    previousHandler(){
        if(this.currentPage > 1){
            this.currentPage = this.currentPage - 1;
            this.updateRecords();
        }
    }

    firstPageHandler(){
        if(this.currentPage > 1){
            this.currentPage = 1;
           
            this.updateRecords(1);
           
        }
    }

    lastPageHandler(){
        this.currentPage = this.totalPage;
        this.updateRecords();
    }

    //when clicking on a number page
    thisPageHandler(event){
        if(event.target.currentpage){
            this.currentPage = event.target.currentpage;
            //disable current page
            event.target.disabled = true;

            this.disabledPageNumbers.push(this.currentPage);
            this.updateRecords();
        }
    }
    //this method is responsible for creating the buton pages that we want to expose on client side, 
    //let's say we want to expose just 5 number buttons then we set totalPageNumbers = 5; and that is it. 
    //then the the html foreach will only generate these pages like 1,2,3,4,5
    //when we click on page 5 for example then the next 4 pages will be displayed like 5,6,7,8,9, in total 5 with current page.
    calculateVisiblePageNumbers(){
        this.pageNumbers = [];
        this.nrPagesLeft = (this.totalPage - this.currentPage);
        //this.totalPageNumbers - 1; just to make sure when we set above on the top the totalPageNumbers = 3 
        //then we expect 3 number buttons to apear on page
        //this.totalPage = total pages 
        for(let i = 0; i <= this.totalPageNumbers - 1; ++i){
            if(i <= this.totalPage && i <= this.nrPagesLeft){
                this.pageNumbers.push(i + this.currentPage);
            }
        }
        return this.pageNumbers;
    }

    get disablePrevious(){
        return this.currentPage <=1;
    }

    get disableNext(){
        return this.currentPage >= this.totalPage;
    }
  
    get lastLabelPage(){
        return "Last Page "+ this.totalPage;
    }

    get disableLastPage(){
        return this.currentPage >= this.totalPage;
    }
    get disableFirstPage(){
        return this.currentPage === 1;
    }


    updateRecords(){
        const start = (this.currentPage - 1) * this.recordSize; 
        // when page is 1 the start index will be 0, when page is 2 the start index will be 5, where 1 * 5 = 5 (where 5 is sixth element from total records list)
        const end = this.recordSize * this.currentPage; 
        //when record type is 5 and multipling with curent page 1 then the end will be 5, if current page is 2 then * 5 the end will be 10; 
      
        //slice() always generates a new copy 
        this.visibleRecords =  this.totalRecords.slice(start, end);
        this.dispatchEvent(new CustomEvent('update',{
            detail: {
                records: this.visibleRecords
            }
        }))
       
        this.enablePreviouslyDisabledButtons();
        this.calculateVisiblePageNumbers();
    }

    enablePreviouslyDisabledButtons(){
        const buttonElements = this.template.querySelectorAll('lightning-button');//all buttons from child component
        for (const button of buttonElements) {
            if(this.isEligibleNumericPageButton(button)){
                 //enabling all buttons that are disabled
                button.disabled = false;
            }
        }
    }
    
    //this function makes sure the button is not current and is a numeric button
    isEligibleNumericPageButton(button){
        return button.currentpage !== this.currentPage && button.disabled && button.label !== "Previous" && button.label !== "Next";
    }
}
pagination.js

The pagination.js file is designed to facilitate easy navigation through large datasets in Salesforce. Here’s a high-level overview of its functionality:

Initialization:

To start off, the component initializes with default values, such as the current page number, total number of records, and record size per page. Moreover, it includes methods to handle navigation actions, allowing users to effortlessly move to the next or previous page, go to the first or last page, and select a specific page.

Record Display:

Moving on to the record display, the component fetches records based on the current page and record size, ensuring that only a subset of records is displayed at any given time. Furthermore, it dynamically updates the displayed records as users navigate through pages.

Page Navigation:

For seamless navigation, navigation buttons are provided to easily transition between pages, including buttons for navigating to the first, previous, next, and last pages. Additionally, numerical buttons are generated dynamically based on the total number of pages, enabling users to jump to specific pages directly.

Customization:

In terms of customization, the component offers flexibility to work with different datasets and record sizes by adjusting the configuration parameters. This allows developers to seamlessly integrate the Pagination Component into various LWC projects with minimal effort, enhancing the overall user experience when dealing with large datasets.

Overall, the Pagination Component simplifies the implementation of pagination functionality in LWC applications, making it accessible and user-friendly for Salesforce professionals of all levels, including administrators, business analysts, quality assurance testers, and developers.

More About UpdateRecords()

 updateRecords(){
        const start = (this.currentPage - 1) * this.recordSize; 
        // when page is 1 the start will be 0, when page is 2 the start will be 1 * 5 = 5 (where 5 is sixth element from total records)
        const end = this.recordSize * this.currentPage; 
        //when record type is 5 and multipling with curent page 1 then the end will be 5, if current page is 2 then * 5 the end will be 10; 
      
        //slice() always generates a new copy 
        this.visibleRecords =  this.totalRecords.slice(start, end);
        this.dispatchEvent(new CustomEvent('update',{
            detail: {
                records: this.visibleRecords
            }
        }))
       
        this.enablePreviouslyDisabledButtons();
        this.calculateVisiblePageNumbers();
    }
JavaScript

The updateRecords() method is responsible for updating the displayed records based on the current page and record size settings. Here’s a breakdown of its functionality:

Calculating Start and End Index:

  • The method calculates the start and end indices of the records to be displayed on the current page.
  • The start index is determined by subtracting 1 from the current page number and then multiplying by the record size.
  • For example, if the current page is 1 and the record size (records displayed per page) is 5, the start index will be 0 (1 – 1 = 0) for the first page. Why 0, well because we all know 0 is the first element in our records list.
  • The end index is calculated by multiplying the record size by the current page number. By default, the current page is 1.
  • For instance, if the current page is 2 and the record size is 5, the end index will be 10 (5 * 2 = 10).

Extracting Records:

  • The slice() method is used to extract a subset of records from the total records array.
  • It takes the start and end indices calculated earlier and returns a new array containing the records to be displayed on the current page.

Dispatching Event:

  • After updating the visible records, a CustomEvent named ‘update’ is dispatched.
  • This event contains details about the updated records, which can be consumed by parent components or listeners.

Enabling Buttons and Updating Page Numbers:

  • The method calls two helper functions, enablePreviouslyDisabledButtons() and calculateVisiblePageNumbers().
  • enablePreviouslyDisabledButtons() ensures that all previously disabled pagination buttons are enabled.
  • calculateVisiblePageNumbers() recalculates the visible page numbers based on the updated pagination settings.

Overall, updateRecords() efficiently manages the display of records on the current page, ensuring a seamless user experience when navigating through the dataset.

Preparing child pagination.html file

Copy the bellow pagination.html code and replace and paste it into Lightning Studio pagination.html

pagination.html file
pagination.html file
<template>
    <lightning-layout>
          <!-- GO TO FIRST PAGE -->
       <lightning-layout-item>
        <lightning-button 
                label="First Page"
                onclick={firstPageHandler}
                disabled={disableFirstPage}>
            </lightning-button>
       </lightning-layout-item> 
        <!-- GO TO PREVIOUS PAGE -->
       <lightning-layout-item>
            <lightning-button 
                label="Previous" 
                icon-name="utility:chevronleft"
                onclick={previousHandler}
                disabled={disablePrevious}>

            </lightning-button>
       </lightning-layout-item> 
       <!-- Go To Page Number # -->
       <template for:each={pageNumbers} for:item="page">
            <lightning-button id={page}
                label={page} 
                onclick={thisPageHandler}
                key={page} 
                currentpage={page}
                >
            </lightning-button>
       </template>

        <!-- NEXT PAGE -->
       <lightning-layout-item>
        <lightning-button 
                label="Next" 
                icon-name="utility:chevronright"
                onclick={nextHandler}
                disabled={disableNext}>
            </lightning-button>
       </lightning-layout-item> 
       <!--GO TO LAST PAGE -->
       <lightning-layout-item>
        <lightning-button 
                label={lastLabelPage} 
                onclick={lastPageHandler}
                disabled={disableLastPage}>
            </lightning-button>
       </lightning-layout-item> 

    </lightning-layout>
</template>
pagination.html

Save then Deploy

Preparing the Parent Component that will use the above reusable pagination component.

Creating the parent accountPagination LWC Component

Now, let’s focus here because this is where we’ll learn how to utilize the pagination LWC created earlier. We’ll create the LWC component to display our records, with 5 records per page, whether it’s accounts, leads, or custom object records.

In Lightning Studio click on Create New Component:

  • component name: paginationDemo
  • isExposed: checked
  • targets: Record Page, App Page, Home Page depending on where you want to use the component, for now, you can select all or just App Page

Deploy the component.

Preparing parent PaginationDemo.js file

Now we will copy and paste the paginationDemo.js

paginationDemo.js file
paginationDemo.js file
import { LightningElement, wire} from 'lwc';
import getAccountList from '@salesforce/apex/PaginationController.getAccountList';

export default class PaginationDemo extends LightningElement {
    visibleAccounts
    totalAccounts

    @wire(getAccountList)
    wiredAccount({error, data}){
        if(data){
            this.totalAccounts = data;
            console.log(this.totalAccounts);
        }
        if(error){
            console.error(error);
        }
    }

    updateAccounttHandler(event){
        this.visibleAccounts=[...event.detail.records];
        //records passed in the child component
        console.log(event.detail.records);
    }
}
JavaScript

In this section, we will continue writing the content for our PaginationDemo component in Lightning Web Components. We have already imported the necessary modules and set up a wire method to fetch account data from an Apex controller. Now, we will create a visibleAccounts property and a totalAccounts property to store our fetched data.

The visibleAccounts property will hold the list of accounts that will be displayed on our page, while the totalAccounts property will hold the entire list of accounts retrieved from the database. Next, using the @wire decorator, we call our getAccountList method from the Apex controller and assign its returned value to the wiredAccount variable.

Inside this variable, we have access to both error and data properties. In case there is an error while fetching the data, we can display an error message to the user. Otherwise, we can set our visibleAccounts property to the retrieved data and our totalAccounts property to the complete list of accounts.

Next, we will create a template element in our HTML file and use the for:each directive to loop through our visibleAccounts list and display each account’s information. Additionally, we can add filters and sorting options by utilizing JavaScript functions to manipulate our visibleAccounts property before displaying it on the page.

By separating our code into different Web Components, we are able to easily manage and update specific functionalities without affecting other parts of our application. This modular approach also allows for better reusability as these components can be used in multiple pages or applications.

Preparing parent PaginationDemo.html file


Copy and paste the below html code in LightningStudio paginationDemo.html

PaginaionDemo component created
PaginationDemo component created
<template>
    <lightning-card title="Pagination demo Accounts" icon-name="custom:custom63"> 
        <div class="slds-var-m-around_medium">
            <template if:true={visibleAccounts}>
                <template for:each={visibleAccounts} for:item="account">
                    <p key={account.Id}>{account.Name}</p>
                </template>
            </template>
            <div slot="footer" class="slds-var-m-vertical_medium">
                <!-- when we want to call an event method we name the attribut starting with on.. then the event name update i.e onupdate -->
                <c-pagination records={totalAccounts} onupdate={updateAccounttHandler}>

                </c-pagination>
            </div>
        </div>
    </lightning-card>
</template>
PaginationDemo.html

This Lightning Web Component (LWC) template represents a demonstration of pagination for accounts. Here’s a description of its structure and functionality:

Lightning Card:

  • The component is enclosed within a lightning-card element with the title “Pagination demo Accounts” and an icon named “custom:custom63”.

Record Display:

  • Within the card body, records from the visibleAccounts array are iterated over using a template for:each directive.
  • Each account’s name is displayed using a paragraph (<p>) element, with the key attribute set to the account’s ID to ensure efficient rendering.

Pagination Component:

  • The Pagination Component (c-pagination) is included in the card’s footer using a div with the slot attribute set to “footer”.
  • The records attribute is bound to the totalAccounts property, which represents the total set of accounts to paginate.
  • An onupdate event handler (updateAccounttHandler) is specified to handle updates triggered by the Pagination Component.

Event Handling:

  • When an update event is emitted by the Pagination Component, the updateAccounttHandler method is invoked to handle the update.
  • This event handler can be defined in the JavaScript file associated with this template to perform any necessary actions based on the updated records.

Overall, this template provides a user-friendly interface for navigating through a list of accounts using pagination, enhancing the readability and usability of the displayed records.


The “records” attribute specifies the total number of accounts available, while the “onupdate” attribute calls a method called “updateAccountHandler” when any changes are made to the pagination and it uses the totalAccounts list to slice the necessary records for a specific page. For example, if the current page is 1 and we expose 5 records per page, it will slice Accounts from 0 to 4 from totalAccounts, and when navigating to page 2 then it will slice from 5 to 9, and so on. Remember, 0 is the 1st element from the list.

How to expose more or less page number buttons?

What if you want to customize the number of buttons displayed on the pagination component? For instance, opting to show only three number buttons like this

Pagination Example 3 Number Buttons

It’s a simple adjustment: navigate to the pagination.js file and assign the number 3 to the totalPageNumbers property:

import { LightningElement, api} from 'lwc';

export default class Pagination extends LightningElement {
    currentPage = 1;
    totalRecords
    totalPageNumbers = 3 //Modify this number to specify the desired number of page number buttons to display.
pagination.js


In Lightning Studio the js file would look like this:

Pagination Example Change Displayed Number Buttons Lightning Studio pagination.js file
Pagination Example Change Displayed Number Buttons Lightning Studio pagination.js file

Or, if you don’t need the last, first, previous, or next buttons, just go to pagination.html file and comment out the button you don’t need. Let’s say we don’t need the Last Button, then we just need to comment the lightning-layout-item is located just below of the <!--GO TO LAST PAGE --> comment.

       <!--GO TO LAST PAGE -->
       //<lightning-layout-item>
       // <lightning-button 
       //         label={lastLabelPage} 
       //         onclick={lastPageHandler}
       //         disabled={disableLastPage}>
       //     </lightning-button>
       //</lightning-layout-item> 
pagination.html

How to display more than 5 records per current page?


When it comes to deciding and changing the number of records, cards, articles, or news blocks that you want to display per page then all you have to do is to change the @api recordSize = 5 parameter from 5 to the desired number. Let’s say we want to expose 10 Accounts, then navigate to pagination.js the file and change it.

import { LightningElement, api} from 'lwc';

export default class Pagination extends LightningElement {
    currentPage = 1;
    totalRecords
    totalPageNumbers = 5
    pageNumbers = [];
    disabledPageNumbers = [];
    nrPagesLeft = 0;
  
    @api recordSize = 10 //here you do the change so that to display the x # of records per page
pagination.js

Save and deploy.

Pagination in action

Assuming we are logged in in a Salesforce Org, we will create an App Page and will drag and drop our component to app page and will then be able to navigate through our accounts.
1. Go to setup, and type – App Builder and choose Lightning App Builder
2. Click New and Select App Page then click Next

Creating App Page
Creating App Page

3. Then, name it Account Pagination click next, and choose a standard page layout view for example Header and Left Sidebar and click Done.

Selecting Standard Page Layout template
Selecting Standard Page Layout template

4. From the Left Side Panel find the paginationDemo component, drag and drop it into the top section of the page:

Drag and drop paginationDemo component on the App Page
Drag and drop paginationDemo component on the App Page

5. Then, click Save then Activate, and when the pop-up windows appear choose the Lightning Experience tab, then select Sales app in the “Add to Lightning Apps” section then click on “Add page to app” from Lighninginstrumentation section, then Save. Now the Account Pagination is added in the Sales app. Navigate to your Sales App and see your App Page’s Pagination in action and test it.

Account Pagination in Action
Account Pagination in Action

Play Around with the buttons and test each of them, and if you want more customized functionality let me know in the comments or connect with me on Linkedin, and we can discuss and adjust as per your needs.

How this approach can be reusable?

Hence, the Pagination Component (c-pagination) along with its associated JavaScript file (pagination.js) and HTML file (pagination.html) can be reused across various Salesforce projects or pages. This modular approach facilitates seamless integration of pagination functionality into different Lightning Web Components (LWCs) within the Salesforce ecosystem.

By abstracting the pagination logic into a separate component, developers can minimize code duplication and streamline development efforts across multiple projects, thereby enhancing productivity and code maintainability.These files contain the logic and functionality for pagination, which can be imported and utilized in various Lightning Web Components (LWCs) within the Salesforce environment.

By encapsulating the pagination logic into a standalone component, developers can easily integrate it into different projects without needing to rewrite the code. Additionally, the configuration parameters within the pagination.js file, such as record size and number of page buttons, can be customized to suit specific requirements, further enhancing reusability.


In summary, this guide offers an easy solution for adding pagination to Salesforce Lightning Web Components (LWC). With customizable features and clear instructions, users can navigate data effortlessly, improving productivity and user experience.

Similar Posts

Leave a Reply

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