jQuery Pagination — Complete Guide to Building Page Navigation
In this tutorial, you will learn about jquery pagination. We cover key concepts, practical examples, and best practices to help you master this topic.
jQuery pagination splits large data sets into manageable pages, providing Previous/Next buttons, page number links, and configurable page sizes for better user experience and performance.
What You'll Learn
- Implementing client-side pagination logic
- Rendering page navigation controls
- Handling page changes and data updates
- Building reusable pagination plugins
- Pagination with AJAX and server-side data
Why It Matters
Displaying 1000 items on one page overwhelms users and hurts performance. Pagination improves load time, reduces DOM size, and helps users navigate content in digestible chunks.
Real-World Use
A search results page that shows 20 results per page with Previous/Next buttons, numbered pages with ellipsis for large ranges, and a "Results X-Y of Z" summary.
Pagination Flow
flowchart TD
A[Data Array] --> B[Set Page Size]
B --> C[Calculate Total Pages]
C --> D[Slice Data for Current Page]
D --> E[Render Current Page Items]
E --> F[Render Pagination Controls]
F --> G[User Clicks Page N]
G --> D
style D fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px
Basic Pagination Logic
function Pagination(data, pageSize) {
this.data = data;
this.pageSize = pageSize || 10;
this.currentPage = 1;
this.totalPages = Math.ceil(data.length / this.pageSize);
this.getCurrentPageData = function() {
var start = (this.currentPage - 1) * this.pageSize;
var end = start + this.pageSize;
return this.data.slice(start, end);
};
this.goToPage = function(page) {
if (page < 1 || page > this.totalPages) return;
this.currentPage = page;
return this.getCurrentPageData();
};
this.nextPage = function() {
return this.goToPage(this.currentPage + 1);
};
this.prevPage = function() {
return this.goToPage(this.currentPage - 1);
};
}
// Usage
var data = [];
for (var i = 1; i <= 100; i++) {
data.push({ id: i, name: 'Item ' + i });
}
var pagination = new Pagination(data, 10);
console.log('Page 1:', pagination.getCurrentPageData());
console.log('Page 2:', pagination.goToPage(2));
Expected output: The pagination object manages page state. getCurrentPageData() returns a slice of the data array for the current page.
Rendering Pagination Controls
function renderPagination(pagination, $container) {
$container.empty();
// Previous button
var $prev = $('<button>')
.text('Previous')
.prop('disabled', pagination.currentPage === 1)
.on('click', function() {
pagination.prevPage();
updateUI(pagination);
});
$container.append($prev);
// Page numbers
for (var i = 1; i <= pagination.totalPages; i++) {
var $pageBtn = $('<button>')
.text(i)
.addClass(i === pagination.currentPage ? 'active' : '')
.on('click', function() {
var page = parseInt($(this).text());
pagination.goToPage(page);
updateUI(pagination);
});
$container.append($pageBtn);
}
// Next button
var $next = $('<button>')
.text('Next')
.prop('disabled', pagination.currentPage === pagination.totalPages)
.on('click', function() {
pagination.nextPage();
updateUI(pagination);
});
$container.append($next);
}
function updateUI(pagination) {
var pageData = pagination.getCurrentPageData();
// Render items
var $list = $('#item-list').empty();
pageData.forEach(function(item) {
$list.append('<li>' + item.name + '</li>');
});
// Re-render pagination (to update active state)
renderPagination(pagination, $('#pagination-controls'));
}
// Initialize
var pagination = new Pagination(data, 10);
renderPagination(pagination, $('#pagination-controls'));
updateUI(pagination);
Pagination with Ellipsis
function renderPageNumbers(pagination, $container) {
var total = pagination.totalPages;
var current = pagination.currentPage;
var range = 2; // Pages to show around current
var pages = [];
// Always show first page
pages.push(1);
// Calculate range
var start = Math.max(2, current - range);
var end = Math.min(total - 1, current + range);
// Ellipsis before range
if (start > 2) pages.push('...');
// Middle pages
for (var i = start; i <= end; i++) {
pages.push(i);
}
// Ellipsis after range
if (end < total - 1) pages.push('...');
// Always show last page
if (total > 1) pages.push(total);
// Render
pages.forEach(function(page) {
if (page === '...') {
$container.append('<span class="ellipsis">...</span>');
} else {
var $btn = $('<button>')
.text(page)
.addClass(page === current ? 'active' : '')
.on('click', function() {
pagination.goToPage(page);
updateUI(pagination);
});
$container.append($btn);
}
});
}
Expected output: For a 50-page set on page 25, the page numbers show: 1 ... 23 24 [25] 26 27 ... 50.
AJAX Pagination (Server-Side)
function ServerPagination($container, options) {
this.$container = $container;
this.pageSize = options.pageSize || 20;
this.currentPage = 1;
this.totalPages = 1;
this.apiUrl = options.apiUrl;
this.loading = false;
this.loadPage = function(page) {
if (this.loading) return;
this.loading = true;
this.currentPage = page;
this.$container.addClass('loading');
$.ajax({
url: this.apiUrl,
data: { page: page, pageSize: this.pageSize },
method: 'GET'
}).done($.proxy(function(response) {
this.totalPages = response.totalPages;
this.renderItems(response.items);
this.renderControls();
}, this)).always($.proxy(function() {
this.loading = false;
this.$container.removeClass('loading');
}, this));
};
this.renderItems = function(items) {
// Render item template
};
this.renderControls = function() {
// Render pagination buttons
};
this.loadPage(1);
}
Configurable Pagination Plugin
$.fn.pagination = function(options) {
var settings = $.extend({
pageSize: 10,
data: [],
onPageChange: null
}, options);
return this.each(function() {
var $container = $(this);
var currentPage = 1;
var totalPages = Math.ceil(settings.data.length / settings.pageSize);
function getPageData(page) {
var start = (page - 1) * settings.pageSize;
var end = start + settings.pageSize;
return settings.data.slice(start, end);
}
function render() {
$container.empty();
var pageData = getPageData(currentPage);
// Callback
if ($.isFunction(settings.onPageChange)) {
settings.onPageChange(pageData, currentPage, totalPages);
}
// Navigation
var $nav = $('<div class="pagination-nav">');
var $prev = $('<button class="prev">Previous</button>')
.prop('disabled', currentPage === 1)
.on('click', function() {
if (currentPage > 1) {
currentPage--;
render();
}
});
$nav.append($prev);
for (var i = 1; i <= totalPages; i++) {
(function(page) {
$nav.append(
$('<button>').text(page)
.addClass(page === currentPage ? 'active' : '')
.on('click', function() {
currentPage = page;
render();
})
);
})(i);
}
var $next = $('<button class="next">Next</button>')
.prop('disabled', currentPage === totalPages)
.on('click', function() {
if (currentPage < totalPages) {
currentPage++;
render();
}
});
$nav.append($next);
$container.append($nav);
}
render();
});
};
// Usage
$('#pagination-container').pagination({
pageSize: 5,
data: myData,
onPageChange: function(pageData, page, totalPages) {
$('#page-info').text('Page ' + page + ' of ' + totalPages);
$('#items').empty();
pageData.forEach(function(item) {
$('#items').append('<li>' + item.name + '</li>');
});
}
});
Items-Per-Page Selector
$('#page-size-select').on('change', function() {
var newSize = parseInt($(this).val());
pagination.pageSize = newSize;
pagination.totalPages = Math.ceil(pagination.data.length / newSize);
pagination.currentPage = 1;
updateUI(pagination);
});
// HTML:
// <select id="page-size-select">
// <option value="10">10 per page</option>
// <option value="20">20 per page</option>
// <option value="50">50 per page</option>
// </select>
Common Mistakes
Not resetting to page 1 when data changes - When filtering or sorting the data, reset
currentPageto 1. Otherwise, the user may be on a page that no longer exists.Forgetting to recalculate totalPages - After data changes, recalculate
totalPages = Math.ceil(data.length / pageSize)before checking bounds.Rendering all page buttons for large datasets - 1000 pages with 1000 buttons is unusable. Use ellipsis to collapse the range.
Not disabling Previous/Next at boundaries - Previous should be disabled on page 1. Next should be disabled on the last page. This provides clear affordance.
Off-by-one errors in slicing - Data slicing is zero-based:
start = (page - 1) * pageSize,end = start + pageSize. Page 1 starts at index 0.
Practice Questions
- How do you calculate the start and end index for a given page?
- Why should you reset to page 1 when the data array changes?
- How do you handle pagination with ellipsis for large page ranges?
- What is the difference between client-side and server-side pagination?
- How do you implement an items-per-page selector?
Challenge: Build a complete product catalog with client-side pagination, a page size selector (10/20/50), ellipsis page numbers, Previous/Next buttons, a search filter that resets pagination, and a "Results X-Y of Z" display.
FAQ
Mini Project
Build a searchable, paginated product table with 200 sample products. Include a search input that filters products by name, a page size selector (10, 20, 50), pagination controls with ellipsis, and a summary line showing "Showing X-Y of Z products".
What's Next
Data presentation is key. Learn how jQuery effects add transitions and visual polish to pagination and other UI components.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro