
So far, we have covered how to make a table, sort a table, and search a table. One more feature we can implement to improve navigation is LWC table pagination. Pagination is when the table only displays a subset of records. Users navigate through the table using numbers, representing pages in the table, or arrows. Pagination is also used when too much data is being returned and needs to be split up, usually for performance reasons.
Implementing pagination can be done in two ways, which we will cover in this article:
- Returning all records and paginating the result.
- Calling events when the table is navigated through to get records in real-time, which are then displayed in paginated fashion.
Method 1 is an easy to implement, simple method that will make your data much more manageable to interact with. Method 2 is harder to implement, but necessary for really large sets of data. You can’t return and process hundreds of thousands of records to make a table!
LWC Table Pagination On All Returned Records
Let’s create a table of Accounts and render them on a page:
HTML:
<template>
<div>
<table class='slds-table'>
<thead>
<tr>
<th>
<a data-id="Id">
<div>Id</div>
</a>
</th>
<th>
<a data-id="Name">
<div>Name</div>
</a>
</th>
</tr>
</thead>
<tbody>
<template for:each={searchable} for:item="account">
<tr key={account.Id}>
<td key={account.Id}>
{account.Id}
</td>
<td key={account.Name}>
{account.Name}
</td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
Javascript:
import { LightningElement, api, track } from 'lwc';
import getAccountApex from "@salesforce/apex/GetPeople.GetAccount";
export default class SortedTable extends LightningElement {
@track Accounts;
@track searchable;
constructor(){
super();
getAccountApex().then(result => {
this.Accounts = result;
this.searchable = this.Accounts;
});
}
}

This is a pretty simple table that is displaying 100 Account records. You can see pretty quickly that it is not the best way to show this much data. Ideally, you would want there to be pages, showing a set number of records at a time.
To implement pagination, lets put some buttons under the bottom-right side of the table (this code is pasted under the closing table tag):
<div style="float: right;">
<button style="margin-right: 10px;">
<lightning-icon icon-name="utility:chevronleft"></lightning-icon>
</button>
<button>
<lightning-icon icon-name="utility:chevronright"></lightning-icon>
</button>
</div>
The buttons won’t do anything yet, but let’s start by limiting the records to 15 per page:
@track Accounts;
@track searchable = [];
pageLength = 15;
page = 1;
constructor(){
super();
getAccountApex().then(result => {
this.Accounts = result;
for(let i = 0; i < this.pageLength; i++){
this.searchable.push(this.Accounts[i]);
}
});
}

Now, when you click on either of the buttons, we want the table to go to that page of results. Let’s put an onclick event on each button that displays the next or previous set of results:
HMTL
<div style="float: right;">
<button style="margin-right: 10px;" onclick={prevpage}>
<lightning-icon icon-name="utility:chevronleft" onclick={prevpage}></lightning-icon>
</button>
<button>
<lightning-icon icon-name="utility:chevronright" onclick={nextpage}></lightning-icon>
</button>
</div>
JS
nextpage(){
let results = [];
if(this.page <= (Math.floor(this.Accounts.length/this.pageLength))){
this.page = this.page + 1;
for(let i = 0; i < this.pageLength; i++){
if((i + (this.page * this.pageLength)) < this.Accounts.length){
results.push(this.Accounts[i + (this.page * this.pageLength)]);
}
}
this.searchable = results;
}
}
prevpage(){
let results = [];
if(this.page >= 1){
this.page = this.page - 1;
for(let i = 0; i < this.pageLength; i++){
if((i + (this.page * this.pageLength)) < this.Accounts.length){
results.push(this.Accounts[i + (this.page * this.pageLength)]);
}
}
this.searchable = results;
}
}
And you can see we can now navigate through the table! With this logic in place, we navigate to any page in the table regardless if it has the same amount of records as the pageLength.

By using a combination of page and pageLength, we can always figure out what index we need to start grabbing data from to render the next or previous page. With a few logic checks, the code can iterate over the necessary amount of records and display them. Also, by assigning pageLength to a variable, you can easily change the amount of records being displayed by simply changing the value of pageLength.
LWC Table Pagination By Making Server Calls
The other method of LWC table pagination is done by making a server call to get the data needed to display in the table when the next and previous buttons are clicked. This method is implemented when working with large sets of data that make querying the entire data set at once impractical.
We can use the above code and make a few changes to the nextpage() and prevpage() methods. These will need to be server calls instead that fire SOQL queries back to the database and return the necessary records only, which will then be rendered on the page:
nextpage(){
this.page = this.page + 1;
getNextPageApex({pageLength: this.pageLength, page: this.page}).then(result => {
this.searchable = result;
});
}
prevpage(){
if(this.page >= 1){
this.page = this.page - 1;
getPrevPageApex({pageLength: this.pageLength, page: this.page}).then(result => {
this.searchable = result;
});
}
}
To make server-side calls, the methods need to be created on an Apex controller and imported into the Javascript file of your component:
import getNextPageApex from "@salesforce/apex/GetPeople.GetNextPage";
import getPrevPageApex from "@salesforce/apex/GetPeople.GetPrevPage";
The methods themselves are defined on the controller as:
@AuraEnabled
public static List<Account> GetNextPage(Integer pageLength, Integer page) {
Integer offset = pageLength * page;
List<Account> accounts = [Select Id, Name FROM Account LIMIT :pageLength OFFSET :offset];
return accounts;
}
@AuraEnabled
public static List<Account> GetPrevPage(Integer pageLength, Integer page) {
Integer offset = pageLength * page;
List<Account> accounts = [Select Id, Name FROM Account LIMIT :pageLength OFFSET :offset];
return accounts;
}
Now, when you click on the buttons, the table will cycle through the results!

Looking at the code, there’s a few things to note:
- The JS calls to the server pass parameters into the Apex methods using the syntax importedFuntionName({param1: value, param2: value})
- The name of the parameters is whatever the name of the value is on the server side
- The return of the call is handled using Promise syntax (then(result =>{})
- The server-side call uses the LIMIT and OFFSET properties of SOQL queries to get the necessary data, simplifying the data handling. LIMIT imposes a limit on the amount of records returned up to the value and OFFSET specifies an offset for the results returned from the query
Using either method, you can see the advantage of implementing LWC table pagination. It makes your data easier to handle for you and your end user.
This code is not working properly. It is Skipping values in between Kindly rectify the code.
Can you post a few screenshots of what is happening?
Hello, the following snippet fixes the skipping of results.
nextpage(event) {
let results = [];
if (this.page = 1) {
this.page = this.page – 1;
results = this.Accounts.slice((this.page – 1) * this.pageLength, this.page * this.pageLength);
this.searchable = results;
}
}