Updated on May 4, 2021 to add a second solution, based on JSON data.
Updated on August 30, 2019 to use the new ES syntax.
Updated on May 25, 2018 to hide Next and Previous links on first and last page.
Table of contents
Server-side pagination is needed when you have to display hundreds of records. You may fetch results from a database using an offset and loading a single page for each HTTP request.
A long time ago, I migrated from List.js to server-side pagination in order to scale a massive result set. For smaller ones – less than 1000 – and when the query is optimized, you can use client-side navigation (i.e., JavaScript pagination).
JavaScript Pagination – Solution #1
If your result set is small, it’s possible to fully load it. In my case, I have an HTML table (a div
-based structure is also possible) which needs to be paginated.
Usage
To use this JavaScript pagination script, follow the steps below:
How to implement JavaScript pagination?
- Add the JavaScript to your page footer (see full script below).
- Add CSS to style the navigation bar (see an example below).
- Define an ID on the table you want to scroll.
- Place an empty DOM element where you want to display the navigation bar.
- Initialize the pager.
That’s all.
If you have a huge table, it may be fully displayed before the JavaScript in the footer will be executed. To avoid this, you can set the table as hidden by default using CSS, and make it visible using JavaScript after the pager.showPage()
call.
<table id="pager" class="wp-list-table widefat striped posts">
<thead>
<tr>
<th>Column #1</th>
<th>Column #2</th>
</tr>
</thead>
<tbody>
<tr>
<th>Info #1</th>
<th>Info #2</th>
</tr>
<tr>
<th>Info #1</th>
<th>Info #2</th>
</tr>
<tr>
<th>Info #1</th>
<th>Info #2</th>
</tr>
</tbody>
</table>
<div id="pageNavPosition" class="pager-nav"></div>
<script src="PagerJS.js" defer></script>
<script>
let pager = new Pager('pager', 3);
pager.init();
pager.showPageNav('pager', 'pageNavPosition');
pager.showPage(1);
</script>
JavaScript: PagerJS.js
/* eslint-env browser */
/* global document */
function Pager(tableName, itemsPerPage) {
'use strict';
this.tableName = tableName;
this.itemsPerPage = itemsPerPage;
this.currentPage = 1;
this.pages = 0;
this.inited = false;
this.showRecords = function (from, to) {
let rows = document.getElementById(tableName).rows;
// i starts from 1 to skip table header row
for (let i = 1; i < rows.length; i++) {
if (i < from || i > to) {
rows[i].style.display = 'none';
} else {
rows[i].style.display = '';
}
}
};
this.showPage = function (pageNumber) {
if (!this.inited) {
// Not initialized
return;
}
let oldPageAnchor = document.getElementById('pg' + this.currentPage);
oldPageAnchor.className = 'pg-normal';
this.currentPage = pageNumber;
let newPageAnchor = document.getElementById('pg' + this.currentPage);
newPageAnchor.className = 'pg-selected';
let from = (pageNumber - 1) * itemsPerPage + 1;
let to = from + itemsPerPage - 1;
this.showRecords(from, to);
let pgNext = document.querySelector('.pg-next'),
pgPrev = document.querySelector('.pg-prev');
if (this.currentPage == this.pages) {
pgNext.style.display = 'none';
} else {
pgNext.style.display = '';
}
if (this.currentPage === 1) {
pgPrev.style.display = 'none';
} else {
pgPrev.style.display = '';
}
};
this.prev = function () {
if (this.currentPage > 1) {
this.showPage(this.currentPage - 1);
}
};
this.next = function () {
if (this.currentPage < this.pages) {
this.showPage(this.currentPage + 1);
}
};
this.init = function () {
let rows = document.getElementById(tableName).rows;
let records = (rows.length - 1);
this.pages = Math.ceil(records / itemsPerPage);
this.inited = true;
};
this.showPageNav = function (pagerName, positionId) {
if (!this.inited) {
// Not initialized
return;
}
let element = document.getElementById(positionId),
pagerHtml = '<span onclick="' + pagerName + '.prev();" class="pg-normal pg-prev">«</span>';
for (let page = 1; page <= this.pages; page++) {
pagerHtml += '<span id="pg' + page + '" class="pg-normal pg-next" onclick="' + pagerName + '.showPage(' + page + ');">' + page + '</span>';
}
pagerHtml += '<span onclick="' + pagerName + '.next();" class="pg-normal">»</span>';
element.innerHTML = pagerHtml;
};
}
Sample CSS
.pager-nav {
margin: 16px 0;
}
.pager-nav span {
display: inline-block;
padding: 4px 8px;
margin: 1px;
cursor: pointer;
font-size: 14px;
background-color: #FFFFFF;
border: 1px solid #e1e1e1;
border-radius: 3px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}
.pager-nav span:hover,
.pager-nav .pg-selected {
background-color: #f9f9f9;
border: 1px solid #CCCCCC;
}
JavaScript Pagination – Solution #1 – Demo
See the Pen JavaScript Pagination by Ciprian (@ciprian) on CodePen.
JavaScript Pagination – Solution #2
The second solution is able to get data either manually, client-side generated, or via JSON, server side.
How to implement JavaScript pagination?
- Add the JavaScript to your page footer (see the script below or the Codepen demo).
- Add the HTML template.
- Add your JSON data.
- Initialize the pagination.
The HTML is a simple placeholder for the data:
<div id="listing-table"></div>
<p>
<a href="#" id="btn-prev">Prev</a>
<a href="#" id="btn-next">Next</a>
</p>
<p>Page <span id="page"></span></p>
The JavaScript is split into 3 parts. The pagination helpers functions:
/**
* Get the number of items per page based on the length of the JSON object
* and the number of records per page (set via global variable)
*/
function jsp_num_pages() {
return Math.ceil(jsp_json_object.length / jsp_records_per_page);
}
/**
* Change current page to previous page (-1)
*/
function jsp_prev_page() {
if (jsp_current_page > 1) {
jsp_current_page--;
jsp_change_page(jsp_current_page);
}
}
/**
* Change current page to next page (+1)
*/
function jsp_next_page() {
if (jsp_current_page < jsp_num_pages()) {
jsp_current_page++;
jsp_change_page(jsp_current_page);
}
}
/**
* Change page, display items in
the table and show/hide the navigation buttons.
* This function can be further split into several functional elements, thus
* simplifying the functions and allowing for more complexity (better pagination
* styling, better table layout and so on).
*/
function jsp_change_page(page) {
const btn_prev = document.getElementById('btn-prev');
const btn_next = document.getElementById('btn-next');
const listing_table = document.getElementById('listing-table');
let page_span = document.getElementById('page');
if (page < 1) {
page = 1;
}
if (page > jsp_num_pages()) {
page = jsp_num_pages();
}
listing_table.innerHTML = '';
for (let i = (page - 1) * jsp_records_per_page; i < (page * jsp_records_per_page) && i < jsp_json_object.length; i++) {
listing_table.innerHTML += `${jsp_json_object[i].json_item}<br>`;
}
page_span.innerHTML = `${page}/${jsp_num_pages()}`;
btn_prev.style.display = (page === 1) ? 'none' : 'inline-block';
btn_next.style.display = (page === jsp_num_pages()) ? 'none' : 'inline-block';
}
Finally, we need to initialize the pagination and listen to page changes.
window.onload = () => {
document.getElementById('btn-prev').addEventListener('click', (e) => {
e.preventDefault();
jsp_prev_page();
});
document.getElementById('btn-next').addEventListener('click', (e) => {
e.preventDefault();
jsp_next_page();
});
jsp_change_page(1);
};
This second solution has no styling (for demo purposes) and is more flexible when adding new pagination items.
JavaScript Pagination – Solution #2 – Demo
See the Pen JSP #3 by Ciprian (@ciprian) on CodePen.

Technical SEO specialist, JavaScript developer and senior full-stack developer. Owner of getButterfly.com.
If you like this article, go ahead and follow me on Twitter or buy me a coffee to support my work!
paginator length is very high, if i add more rows. not useful. can i get that fixed.
This is not a final script, though, it’s something to get you started. It can be improved upon and more features can be added, but it’s outside the scope of this article.
How do you use it with multiple tables on the same website?
Which solution are you talking about? I also assume you’re talking about using multiple tables on the same page, not website.
However, the general rule is either to use different table IDs/classes or use a loop to get all table elements.
You’d definitely need to make some changes to both solutions to accommodate multiple tables.
JavaScript Pagination – Solution #2 – Demo
its get only json values in the table
{ json_item: “Item 1”},
{ json_item: “Item 2”},
{ json_item: “Item 3”},
{ json_item: “Item 4”},
{ json_item: “Item 5”},
how to use our html table
What exactly are you saying?
how I take my values in Solution #2’s table.
That depends on how you code your application.
Hi Brother,
I Have A Problem With Script Lines,
************************************************************************
let oldPageAnchor = document.getElementById(‘pg’ + this.currentPage);
oldPageAnchor.className = ‘pg-normal’;
this.currentPage = pageNumber;
let newPageAnchor = document.getElementById(‘pg’ + this.currentPage);
newPageAnchor.className = ‘pg-selected’;
************************************************************************
1-) Here ” document.getElementById(‘pg’ + this.currentPage); ” There is no HTML element with pg id ?
2-) here as a class ” pg-normal ” and ” pg-selected ” You Wrote Description As, But I Couldn’t See Such Option In Css ?
That is the pagination. The code should be dynamically created with all your pages:
1 … 2 … 3 … 4
This is what the `pg + id` code is referring to.