subscribe our youtube channel popup

Pagination in Lightning Web Components (LWC)

Pagination is a critical concept when developing user interfaces that need to present large datasets in a structured, user-friendly way. Whether you’re displaying hundreds of Contacts or a dynamic list of Cases, an effective pagination strategy ensures your Lightning Web Component (LWC) remains fast, responsive, and easy to use. Join us to learn about Pagination in Lightning Web Components (LWC) using client side and server side.

In this blog, we’ll explore:

  • What is pagination and why it matters in LWC
  • Client-side pagination – when and how to use it
  • Server-side pagination – scalable and efficient

What is Pagination?

Pagination is the process of dividing a large dataset into smaller chunks (called pages), which are loaded and displayed separately. Instead of overloading the user interface with all the data at once, you show a manageable number of records per page.

For example, if you have 500 records and show 10 per page, the user can navigate through 50 pages to see all the records.

Why Pagination is important in Salesforce Lightning Web Components (LWC)

  1. Loading large datasets all at once can slow down your app. Pagination fetches only a subset of records at a time, keeping your UI fast and responsive.
  2. Salesforce has strict limits on SOQL queries and heap size. Pagination helps avoid hitting these limits by fetching records in manageable chunks.
  3. Users can easily navigate data in smaller, organized pages instead of scrolling through hundreds of records, improving usability.
  4. As your data grows, paginated components remain stable and scalable, ensuring long-term maintainability of your LWC app.

Two Types of Pagination in Lightning Web Components (LWC)

We’ll look at two main pagination techniques:

  1. Client-side Pagination – fetches all records once and paginates in JS.
  2. Server-side Pagination – fetches only the required data from Apex based on page number and size.

Client-Side Pagination:

Let’s say you need to display up to 50 Contacts in a datatable. Instead of making a call every time the page changes, you fetch all records once and then handle pagination in the component using JavaScript.

Apex Controller:

public with sharing class ContactController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getAllContacts() {
        return [SELECT Id, FirstName, LastName, Email FROM Contact LIMIT 100];
    }
}

HTML (paginationDemo.html):

<template>
    <lightning-card title="Client-Side Pagination">
        <lightning-datatable
            key-field="Id"
            data={paginatedData}
            columns={columns}>
        </lightning-datatable>

        <div class="slds-align_absolute-center slds-m-top_medium">
            <lightning-button label="Previous" onclick={handlePrevious} disabled={isPreviousDisabled}></lightning-button>
            <span class="slds-m-horizontal_medium">Page {currentPage} of {totalPages}</span>
            <lightning-button label="Next" onclick={handleNext} disabled={isNextDisabled}></lightning-button>
        </div>
    </lightning-card>
</template>

JavaScript (paginationDemo.js):

import { LightningElement, track, wire } from 'lwc';
import getAllContacts from '@salesforce/apex/ContactController.getAllContacts';

export default class PaginationDemo extends LightningElement {
    @track contacts = [];
    @track paginatedData = [];
    currentPage = 1;
    pageSize = 10;
    totalPages = 0;

    columns = [
        { label: 'First Name', fieldName: 'FirstName' },
        { label: 'Last Name', fieldName: 'LastName' },
        { label: 'Email', fieldName: 'Email' }
    ];

    @wire(getAllContacts)
    wiredContacts({ data, error }) {
        if (data) {
            this.contacts = data;
            this.totalPages = Math.ceil(data.length / this.pageSize);
            this.updatePaginatedData();
        }
    }

    updatePaginatedData() {
        const start = (this.currentPage - 1) * this.pageSize;
        const end = start + this.pageSize;
        this.paginatedData = this.contacts.slice(start, end);
    }

    handlePrevious() {
        if (this.currentPage > 1) {
            this.currentPage--;
            this.updatePaginatedData();
        }
    }

    handleNext() {
        if (this.currentPage < this.totalPages) {
            this.currentPage++;
            this.updatePaginatedData();
        }
    }

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

    get isNextDisabled() {
        return this.currentPage === this.totalPages;
    }
}


Pagination in Lightning Web Components (LWC)

Once the component is deployed and placed on the record page, the UI will appear as shown in the screenshot. The ‘Previous’ button will be disabled on the first page, and the ‘Next’ button will be disabled on the last page.

Advantages of Client-Side Pagination:

  1. Once data is loaded, navigating between pages is instant, no need to re-fetch data from the server.
  2. Since all data is fetched once, no repeated Apex calls are needed when users switch pages.
  3. You only fetch the data once from Apex, avoiding the complexity of handling page indexes server-side.
  4. Smooth transitions between pages without loading spinners enhance usability.
  5. Ideal when the total record count is small and doesn’t risk hitting client-side limits (like heap size).

Disadvantages of Client-Side Pagination

  1. Fetching all records at once can delay initial rendering—especially for large datasets.
  2. Pulling many records in one Apex call may hit SOQL row limits or heap size limits.
  3. Storing large datasets in the browser (JavaScript memory) can slow down the UI or crash the component.
  4. Since data is loaded once, any changes to records after the initial fetch won’t reflect unless you reload the data.
  5. Client-side pagination doesn’t work well when dealing with thousands of records—server-side is more suitable there.

Server-Side Pagination

When working with thousands of records, it’s not efficient or possible to load everything into the client. Instead, fetch only the data you need per page using SOQL LIMIT and OFFSET.

In server-side pagination in Salesforce LWC, LIMIT and OFFSET in SOQL play a crucial role in fetching a specific “page” of records from the server, instead of retrieving the entire dataset.

How LIMIT and OFFSET Help:

  1. LIMIT:
  • Restricts the maximum number of records returned by the SOQL query.
  • Used to define the page size (e.g., 10 records per page).

SELECT Id, Name FROM Account LIMIT 10

This fetches the first 10 records only.

  1. OFFSET
  • Skips a specific number of records before starting to return rows.
  • Helps in fetching records from the correct position for each page.

SELECT Id, Name FROM Account LIMIT 10 OFFSET 10

This skips the first 10 records and returns the next 10—i.e., records for page 2 (if page size is 10).

Server-Side Pagination Flow with LIMIT and OFFSET:

Page 1: LIMIT 10 OFFSET 0

Page 2: LIMIT 10 OFFSET 10

Page 3: LIMIT 10 OFFSET 20

And so on…

Example: Paginate Contacts via Apex Calls

Apex Controller:

public with sharing class ContactPaginationController {
    @AuraEnabled
    public static List<Contact> getContacts(Integer pageSize, Integer pageNumber) {
        Integer offsetVal = (pageNumber - 1) * pageSize;
        return [
            SELECT Id, FirstName, LastName, Email
            FROM Contact
            ORDER BY CreatedDate DESC
            LIMIT :pageSize OFFSET :offsetVal
        ];
    }

    @AuraEnabled(cacheable=true)
    public static Integer getTotalContacts() {
        return [SELECT COUNT() FROM Contact];
    }
}

HTML (serverPagination.html):

<template>
    <lightning-card title="Server-Side Pagination">
        <lightning-datatable
            key-field="Id"
            data={contacts}
            columns={columns}>
        </lightning-datatable>

        <div class="slds-align_absolute-center slds-m-top_medium">
            <lightning-button label="Previous" onclick={handlePrevious} disabled={isPreviousDisabled}></lightning-button>
            <span class="slds-m-horizontal_medium">Page {currentPage} of {totalPages}</span>
            <lightning-button label="Next" onclick={handleNext} disabled={isNextDisabled}></lightning-button>
        </div>
    </lightning-card>
</template>

JavaScript (serverPagination.js):

import { LightningElement, track } from 'lwc';
import getContacts from '@salesforce/apex/ContactPaginationController.getContacts';
import getTotalContacts from '@salesforce/apex/ContactPaginationController.getTotalContacts';

export default class ServerPagination extends LightningElement {
    @track contacts = [];
    currentPage = 1;
    pageSize = 10;
    totalPages = 0;

    columns = [
        { label: 'First Name', fieldName: 'FirstName' },
        { label: 'Last Name', fieldName: 'LastName' },
        { label: 'Email', fieldName: 'Email' }
    ];

    connectedCallback() {
        this.initPagination();
    }

    async initPagination() {
        const total = await getTotalContacts();
        this.totalPages = Math.ceil(total / this.pageSize);
        this.fetchContacts();
    }

    async fetchContacts() {
        this.contacts = await getContacts({ pageSize: this.pageSize, pageNumber: this.currentPage });
    }

    handlePrevious() {
        if (this.currentPage > 1) {
            this.currentPage--;
            this.fetchContacts();
        }
    }

    handleNext() {
        if (this.currentPage < this.totalPages) {
            this.currentPage++;
            this.fetchContacts();
        }
    }

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

    get isNextDisabled() {
        return this.currentPage === this.totalPages;
    }
}

Advantages of Server-Side Pagination:

  1. Handles thousands of records efficiently without loading everything into memory at once.
  2. Only a small subset of records is loaded into the browser, reducing heap size and improving performance.
  3. Since only a limited number of records are fetched per page, the component loads quickly.
  4. Each page request gets fresh data from the server, reflecting the most recent updates.
  5. Prevents SOQL row and heap size limits by querying only the required chunk of data.

Disadvantages of Server-Side Pagination:

  1. Compared to client-side pagination, each page change may involve a slight delay due to the round trip to the server.
  2. Adds unnecessary complexity if the total number of records is small and can be handled client-side.
  3. Every page navigation sends a new request to the server, which may slightly impact performance if frequent.

Final Thoughts

Pagination is not just a performance tool, it’s also a usability strategy. Whether you choose client-side or server-side depends on your use case and data volume. For most real-world Salesforce apps, server-side pagination is the best practice.

Keep experimenting and make your UI snappy, clean, and scalable! 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: 44

Leave a Reply

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