This walkthrough will take us through standard usage of the simplePagination jQuery plugin by a Flavius Matis.

One thing to note about this plugin, which a few people may get confused about (like Ishan on SO), is that it technically doesn’t implement pagination itself. It generates a page navigator and provides the means, via jQuery events, to simply hook it up to our own pagination functionality.

This guide will take us through installation and a simple use case where we’re paging through rows of a table – showing only rows of that table that belong to the current page.

Hopefully by conclusion you’ll understand the concepts well enough to apply this pagination idea and plugin to your own needs – this may not be a table.. but a list? Could be… body parts of a fish, who knows?



Pick a directory to start from, I’m gonna make a new one in my Sites folder:

mkdir simplePagination
cd simplePagination

I like to separate my files into directories, lets make some more folders:

mkdir css js

Before we get started with any coding, we’ll download the required files and put them into their respective directories.

The files that I speak of are jQuery (as is required by simplePagination, being a jQuery plugin), and of course simplePagination. I’ll skip links as they’ll probably just change in the future :P Google it.

Move jQuery and simplePagination’s JS files to the JS folder. simplePagination also has a CSS file containing it’s themes – move that to the CSS folder.

mv ~/Downloads/jquery-2.0.3.min.js js                                                                                                                                   mv ~/Downloads/.../jquery.simplePagination.js js                                                                                   mv ~/Downloads/.../simplePagination.css css

I like to clean up after myself by deleting the downloaded folder:

rm -r ~/Downloads/...

Now lets get some code out there. Create and start editing an index.html with your favourite text editor:

vim index.html

Keeping it minimal but valid, we’ll start with our HTML declaration and <head>.

<!DOCTYPE html>
    <meta charset="utf-8"/>

Now we’ll link all of those files we downloaded (be careful as the downloaded file names may have changed), and also include a link for a JavaScript file “main.js” that we’ll be creating later with all of our custom code.

    <link rel="stylesheet" type="text/css" href="css/simplePagination.css"/>
    <script src="js/jquery-2.0.3.min.js"></script>
    <script src="js/jquery.simplePagination.js"></script>
    <script src="js/main.js"></script>

For our body we’ll be making a table with some sample data. We need a good way to select page parts and not clash with any other elements. I’m going to add a “paginate” class to our page parts, which are table rows.

I won’t be adding “paginate” to the first row – that’s the header row. If you don’t have a header row and just want to select all rows, consider adding an ID to the table instead of a class to every row, and selecting them like $("#table-id tr") instead of $(".paginate").

      <tr class="paginate">
      <tr class="paginate">
      <tr class="paginate">
      <tr class="paginate">
      <tr class="paginate">
      <tr class="paginate">

The next thing we need to include is the navigation for our pages. This is where the plugin will kick in – we’re not actually making this ourselves, but just coding in a placeholder for it.

    <div id="page-nav"></div>

Easy. That’s our HTML complete, save and exit index.html and move onto our JavaScript file (which we’ve already linked in our <head>). Our task in js/main.js is two, to:

  1. turn that #page-nav placeholder into an actual page navigation; and
  2. connect the page changing event to changing the rows displayed on our table.
vim js/main.js

The only thing you can really tinker with here (if you haven’t diverged from the walkthrough thus far) is the value of perPage; how many TRs should we display per page?

jQuery(function($) {
    // Grab whatever we need to paginate
    var pageParts = $(".paginate");

    // How many parts do we have?
    var numPages = pageParts.length;
    // How many parts do we want per page?
    var perPage = 2;

    // When the document loads we're on page 1
    // So to start with... hide everything else
    // Apply simplePagination to our placeholder
        items: numPages,
        itemsOnPage: perPage,
        cssStyle: "light-theme",
        // We implement the actual pagination
        //   in this next function. It runs on
        //   the event that a user changes page
        onPageClick: function(pageNum) {
            // Which page parts do we show?
            var start = perPage * (pageNum - 1);
            var end = start + perPage;

            // First hide all page parts
            // Then show those just for our page
                     .slice(start, end).show();

Save and exit… and that’s everything, you should now have a functional page navigator.

Further explanation

I’ll explain in more detail a couple of the JavaScript functions used above… this however isn’t specific to the simplePagination plugin.

jQuery .ready()

jQuery(function($) {
    // ...

If you look at the jQuery documentation for the ready function, you’ll see this function can take a few forms. If you look under the heading “Aliasing the jQuery Namespace” you’ll find this particular one (if that heading still exists).

First, this acts as a docready function. This means all code we put within the function($) { } braces will be executed once the DOM document fully loads. This is important when the JavaScript code will operate on DOM content as, if executed before load, the required content may not yet exist and our script won’t operate as expected. It’s almost always a good idea to put your JS code in a docready function.

The second effect is aliasing of the jQuery variable – you may have noticed that we invoke jQuery with the $ variable when inside our docready function. This is useful some cases where multiple jQuerys may accidentally be loaded – which may not be so uncommon in CMSs like WordPress or other platforms that support front-end plugins. If multiple jQuerys are loaded, there could be “namespace clashes” where if you use jQuery multiple times throughout your script, they could be referring to different objects (which may even refer to different versions of jQuery), and this could be problematic.

jQuery(function($) { }); passes the jQuery object to that function under the alias $, hence removing the possibility of clashing with other jQuery objects.

Although this may not be necessary in many cases, it’s not hard work and it is best practice. I recommend you use it.

jQuery .slice()

         .slice(start, end).show();

jQuery’s slice function takes a list of matched elements (like pageParts) and returns only a subset of them which lie within our requested range. We’re invoking this function in two different ways, namely with one or with two parameters.

When the function is called with one parameter (perPage in our case, which evaluates to 2), we’re asking jQuery to slice off all elements BEFORE the 2nd, or keep everything from the 2nd element onwards. The first parameter to .slice() is the start point; where should we start keeping things in this list of elements? Anything before this start point is discarded. Everything from this point and onwards is retained.

Since list indices start from 0, we’re therefore slicing off the first and second elements (which in our case represent the elements in our first page) – leaving us with all page parts which are NOT part of our first page. We then hide those page parts, and we’re done there.

In our second invocation, we’re first taking the full list of page parts and hiding them (pageParts.hide()) and then continuing to slice this list of elements and show the remaining. We’re able to do this in a “connected” manner ($("a").b().c().d()) as all properly made jQuery functions (like hide, show and even the pagination function as from the plugin at subject) return the list of elements to allow continued operation. Some specialty functions (like slice) may return a subset of the original list for us to continue working on, if that’s what it’s designed to do. With that in mind, you can neatly chain up operations as we are above: hiding, slicing then showing.

         .slice(start, end).show();

This second call of slice is now taking two parameters – namely start and end. This functions similarly to the single parameter slice, where we’re starting from the first variable – except where the first invocation would simply continue to the end of the list of elements, here we’re also explicitly specifying an end point in our list. We’ll hence discard all elements before start AND after end – keeping only those between start and end. Seems logical right?

var start = perPage * (pageNum - 1);
var end = start + perPage;

In our case start represents the first element in the newly selected page, and end the first element in the NEXT page. This is because the end point is NOT included in the slice – for those math folks the selection range could be expressed as [start, end). This returns exactly the content of the newly selected page, which we’re then showing.

If you can’t figure out why we use pageNum - 1 in defining our start variable, try to realise that start represents the OFFSET from the first element in our list of page parts that we’d like to slice from. The first page begins with row 0 (programatically), which has an offset of ZERO elements from the beginning of our page part list. If it still doesn’t make sense, try to draw it out on paper :D


Big thanks to Flavius Matis for his open source simplePagination jQuery plugin. Open source is the way to go, woo!

For reference, a similar (but not completely identical) implementation to the above walkthrough can be found in the “simplepagination” directory of this GitHub repository, with extra subdirectories for more complex use cases, including:

  • working with dynamic content;
  • having multiple simplePagination tables on the same page; and
  • working with the URL in navigating to the right page automatically.

If some parts of this walkthrough or the code in the repository above need more elaboration, if you think I missed some points or if you just didn’t understand something, feel free to comment below and I’ll get back to you on that.

So how many body parts of a fish do you know?

Author: Bilal Akil

Husband of Joy. Programming hobbyist and professional.

15 thoughts on “simplePagination”

  1. Hi Bilal,

    Thanks so much for your effort here. It’s helpful and I learned a bit more of jQuery.

    On, if say you click on page 3 then #page-3 is added to the end of the URL. But… if you then refresh the page #page-3 stays up there in the Location box but you go to page 1.

    This is with the latest Firefox on Ubuntu 12.04 LTS.

    I’m trying for a fix.


    1. Hi Mike,

      Although it may seem unfortunate, what you’ve experienced isn’t a bug. For the same reason that we had to implement an onPageClick function ourselves, we’ll have to implement page fragment (# part of the URL) checking functionality here too – the plugin can’t make an assumption on what we want to do here.

      What if we want to scroll down to it or flash it into display or something else on page load? It’s not necessarily the same action as when you click to change page. However in your case, it probably is.

      I’ll provide a solution below, but first I’ll discuss some of the problems to try and explain why it isn’t solved for us.

      It’s a non-trivial problem:
      – What if there were multiple simplePagination elements on the page, which one does that page number refer to? Unfortunately, under the current simplePagination implementation, that’ll refer to the last pager that was clicked (because they’ll each write over the same #page-X fragment), but when you refresh the page there’ll be no way to know which object to update by looking at the URL.
      – It’d be a lot of work to provide all of the required information as part of the page fragment to cover these cases (which object is on which page, etcetera), and it’d make our URLs look very ugly, so its implementation wasn’t included as part of the plugin as some might dislike this functionality. In cases where preserving the page on multiple tables is critical, we still have the means to manage the page fragment ourselves in the onPageClick callback function.

      I hope you understand the problem and why you it’s necessary to solve it yourself for the time being.

      Your solution:
      – Manually check the page fragment. If it exists and matches the right format (use regular expressions to make this check easy), call the selectPage pagination function, which will call your onPageClick function and bring it back up to date.
      – This must be done AFTER initialising the simplePagination object, not before.

      I’ve implemented your solution and put it on GitHub. You can find the example here.

    1. Thanks for posting that Mike.

      You’ve done some great work there! I covered the initial fragment check in my update but I missed the back/forward updating, so excellent job there and thanks for pointing that out :)

      I’ve updated my example from the response to your first comment so it considers the back/forward button being pressed.

      The fragment check also used something called “Regular Expressions” which basically accomplishes your getPageNum function in one line! It’s really handy stuff and I absolutely recommend checking it out.

      I’ve thoroughly commented the part of the code that deals with regular expressions. Once you get the hang of it you can easily write some powerful and elegant code.

      Again, thanks for your input Mike.

  2. Hi bilal, your work is highly appreciable. Can you please help me in the scenario where there is long list of pages are there and after displaying hyperlink for some pages i want to display the dots, as of now all the page number are getting displayed.
    eg : Prev 1 2 3 …8 9 Next

    1. Hi Sahil,

      I believe that behaviour should be automatic once you reach a certain number of pages.

      Looking at the documentation, the displayPages and edges options are probably what you need to customise if the default behaviour isn’t appropriate.

      displayPages is 5 by default, and edges is 2. To me this means that 2 + 5 + 2 = 9 pages will be displayed before any separators will appear. If your use case has less pages, but you’d still like the separators, then customise those values appropriately.

      I will confirm everything I have said once I get access to a computer.

      EDIT: The above assumption was wrong. Read the follow up comment for more details.

    2. Hello again!

      Just checked out the default behaviour for how many pages are needed before a separator appears – it’s a little more complicated than you’d expect…

      I suggest you make a quick mockup and set it to 11 pages – you’ll see how the behaviour works there. The separators change depending on what page you’re currently on – if you’re on page 6 then there’ll be no separator at all, even from one to eleven…

      Once you’ve figured that out, fiddle with the displayPages and edges options I mentioned earlier to try and get a more desired effect.

      Sorry that I couldn’t be of more direct assistance. Let me know if there’s anything else I can clarify.

  3. If you’re dynamically adding or removing content you’ll need to update the paginator to reflect these changes yourself. I’ve whipped up an example for that, running here and with its source code here.

    1. Hi Max,

      There are a few ways to solve this problem. The simplest I could think of would be to write a function that’s responsible for initialising paginators, which uses variable selectors instead of the currently hardcoded ones. With that in place, you can use different identifiers for each table and paginator, and provide them to the function so it can treat them independently of any other tables on the page.

      Here‘s an example, with the source code here.

      Good luck!

Leave a Reply

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