How to create simple Pagination using Lightning components and Apex

Let’s build something every web application needs in their results page: Pagination (aka Paging). This technique is necessary so we don’t bombard our users with all the items in our result page. Instead, we show them in “chunks” or “sets” of results. This is a very simplistic example – all we’re doing is a set of buttons that have page numbers on them. Once clicked, it will go ahead and fetch the results in that page.

A peak at what we’re building is shown below:

Disclaimer: I’m assuming you know how to work with Lightning components. I also hope you know JavaScript and HTML. There’s no downloadable code – you just simply have to follow along.

Lightning Pagination

Currently, there are no built in lightning component for this type of functionality. Instead, we’re using lightning:radioGroup with type “button”. This will setup our page links nicely in a row, with clickable links and active/inactive states already added.

Ready to get started? Let’s begin.

Our Apex methods

First and foremost, let’s start with the backend. If you guys are familiar with SOQL – which is Salesforce’s version of SQL, you know that we have the 3 necessary keywords for our paging to become possible: ORDER BY, LIMIT and OFFSET.

ORDER BY – allows us to determine the order of our results. This makes it so that our result set will always follow a standard sort. This will make our paging deterministic and predictable.

LIMIT – allows us to limit the results in the page. So when we click a page – we will only show these number of records.

OFFSET – allows us to “skip” the records that we will not show. We’re “skipping” these records and start from the first record after our offset.

I’m building a method that I can call from my lightning component. Note the “@auraEnabled” keyword. The function then takes 2 arguments: ofst and lmt. What it returns is simply our queried object, with the results using SOQL.

public static List<sObject> getNewHires(Integer ofst, Integer lmt){
	List<sObject> onBoardingList = [SELECT
						ORDER BY Name DESC
						LIMIT :lmt
						OFFSET :ofst
			return onBoardingList;

Now we need another method to find out the total number of records there are in the database.

public static Integer getTotalItems(){
	Integer total = 0;
	String query = 'SELECT Id ';
	query += 'FROM OnBoarding_Data__c';
	List<sObject> onBoardingList = Database.query(query);
	total = onBoardingList.size();
return total;

The above simply queries our same custom object, returning the total number of records.

My application uses a custom object for “on boarding” employees – so you will see OnBoarding references all through my sample code.

Our simplified Apex is ready. Let’s move to the front end.


 <aura:attribute name="limitPerPage" type="Integer" default="16"/>
 <aura:attribute name="offset" type="Integer" default="0"/>
 <aura:attribute name="pagesArray" type="List" default="[]"/>
 <aura:attribute name="curpage" type="String" default="1"/>

In our HTML, we’re setting up 4 attributes that we need for our pagination. You should be able to tell from their names what they’re for. We’re also setting the default values in them. Note the “pagesArray” attribute – is an array that will house the page objects that we need for our paging system.

<aura:if isTrue="{! v.pagesArray.length > 1 }">
      <div class="pagingRow slds-grid slds-wrap slds-gutters">
      <div aura:id="pagingWrap"
        class="slds-col slds-size_1-of-1 slds-large-size_12-of-12 pagingWrap">
            options="{! v.pagesArray }"

The above is the output of our code. You see div wrappers that have Lighting Design System classes, along with aura directives to process our code. Such as our use of the aura:if – which checks the length of our pagesArray. Meaning – we’re only showing paging if there are pages to show.

On a side note, I know developers are always looking for freelance work. I discovered Braintrust: a user-owned talent platform created by and for the world's top talent. Head over to Braintrust and signup today!

You see our use of lightning:radioGroup. We also pass in “value” and “options” – which corresponds to our attributes we defined above.

We also have an onchange attribute calling our “doPaging” handler. We haven’t built this yet, but is coming up.

Let’s move on to our JavaScript.

The JavaScript

Let’s get down to business. We have our markup, we have our Apex waiting in the back end. All we need to do is tie them all up together. We do this with JavaScript – ideally in our helper file.

First, we create a “buildPaging” method. This method ideally fires on page load. But you can also call this method if you have some kind of filter mechanism.

buildPaging : function(component,event, helper){
		helper.callServer(component,'c.getTotalItems', function(response){
			var ttl = response;
			var lmt = component.get('v.limitPerPage');
			var pages = Math.ceil(parseInt(ttl) / parseInt(lmt));
			var pagesArray = [];
			for(var i=1; i<=pages; i++){
				var obj = {};
				obj['label'] = i.toString();
				obj['value'] = i.toString();

First thing you’ll see is our helper.callServer() method. This is basically our means of calling our Apex code above. To find out more about callServer() – see the post “Call Apex from Lightning“.

So from our total records, we can build our pagesArray. We call our getTotalItems from the backend, then we grab our “limitPerPage” attribute. We divide the total by the limit, and we’re doing a “ceil()” on it. This is so that we get a whole new page, even though there’s only 1 item in it.

Lastly, we’re building our pagesArray – but passing in the label and the value as an object.

Note the “toString()” method it. This is due to a bug with
lightning:radioGroup. It can only process strings. If you pass an integer – you would have to click it 2x to take effect! Whatever.

Let’s move on to our handler.

doPaging : function(component, event, helper){
		var lmt = component.get('v.limitPerPage');
		var val = event.getSource().get("v.value");
		var offset = parseInt((val-1) * lmt);
		helper.callServer(component,'c.getNewHires', function(response){
			if(response.length > 0){
			component.set("v.newhires", response);
					console.log('no records');
		},{'ofst' : ofst, 'lmt' : lmt});

So first you see, lmt – which is static (set in our attribute). Then you see “val” – which is what was clicked. We get that number and multiply by the limit – so we get our offset.

We then call our Apex method with those parameters:

{'ofst' : ofst, 'lmt' : lmt}

Inside our callback, we simply set our response to the newly fetched data from our server.


And that’s about it. We’ve just built ourselves a very simplistic pagination using Lightning and Apex. There are many things we can do to enhance our code – like having a “previous” and “next” buttons – but I’ll leave that up to you.

Feel free to comment below.

affiliate link arrowDivi WordPress Theme


  1. Hi Michael!
    Thanks a lot,i am using your approach.
    It works fine,even if now i am facing the offset 2000 limit on SOQL query (we are speaking of about 10000 records to be visuyalized in a lightining component).I don’t know now exactly how many records will be handled (i have to speak about with my client).

  2. Thank you a lot, I appreciate your help
    Can you give me full source of this post? I want to deploy to my org to see how this work!


Leave a Comment.