Pagination is used to break up a block of content into navigable pages on a webpage.
Aside from making it easier to see information, it also helps when loading data from a server. Using pagination, you can decide to only load a fixed number of items each time when the user decides to see them. This helps save time and avoid information overload on a page.
Here’s a sneak peak at the final product:
Our pagination element will use both page numbers and next page & previous page buttons for navigation.
Let’s get started!
1. Place the Content With HTML
In this demo, we’ll be placing the content to be paginated using HTML. In a real life example, we might be getting our content as JSON from a server so we’ll also take a look at how the pagination logic can be applied to this when we’re writing our JavaScript code.
First, we define our paginated content as a list:
<ul id="paginated-list" aria-live="polite"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> ... </ul>
Next we define a nav
element that contains next and previous buttons and the pagination numbers container:
<nav class="pagination-container"> <button class="pagination-button" id="prev-button" title="Previous page" aria-label="Previous page"> < </button> <div id="pagination-numbers"> </div> <button class="pagination-button" id="next-button" title="Next page" aria-label="Next page"> > </button> </nav>
The pagination-numbers div
is empty for now as the page numbers will be determined using JavaScript.
2. Styling with CSS
We’re taking a fairly minimalistic approach for this demo so we’ll only style the pagination numbers and the container.
Place the pagination-container at the bottom of the page, override the default button styling for the pagination number and set an active
class to show which page number is currently selected:
.pagination-container { display: flex; align-items: center; position: absolute; bottom: 0; justify-content: center; } .pagination-number, .pagination-button{ font-size: 1.1rem; background-color: transparent; border: none; margin: 0.25rem 0.25rem; cursor: pointer; height: 2.5rem; width: 2.5rem; border-radius: .2rem; } .pagination-number:hover, .pagination-button:not(.disabled):hover { background: #fff; } .pagination-number.active { color: #fff; background: #0085b6; }
We’ve also added some simple :hover
styling, but use the :not()
selector to make sure it doesn’t apply to the disabled buttons.
3. Pagination Logic with JavaScript
Now to make it work. Let’s define what we’re trying to achieve with pagination:
- Only display a specific number of items on each page
- Display page numbers based on how many times the total items are broken down
- When a page number is clicked, change the display to that page
- Allow navigating to previous and next pages
First, get all the elements we’ll need:
const paginationNumbers = document.getElementById("pagination-numbers"); const paginatedList = document.getElementById("paginated-list"); const listItems = paginatedList.querySelectorAll("li"); const nextButton = document.getElementById("next-button"); const prevButton = document.getElementById("prev-button");
Next, we’ll define our global variables:
-
paginationLimit
: how many items we want displayed on each page; and -
pageCount
: how many pages there will be based on the paginationLimit. -
currentPage
: store the value of the currentPage
Calculate the pageCount
by dividing the total number of items (listItems.length
) by the paginationLimit
and rounding to the highest whole number using the Math.ceil
function.
“The
Math.ceil()
function always rounds a number up to the next largest integer.” – MDN
So if we have 50 items and we only want to display 10 items per page, our page count will be 50/10 = 5 pages. Likewise, if we have 55 items and we want to display 10 items per page, our page count will be 55/10 = 5.5 which rounds up to 6 pages.
const paginationLimit = 10; const pageCount = Math.ceil(listItems.length / paginationLimit); let currentPage;
Add Page Numbers
Now that we know how many pages we’ll need, we can define a function to create a new button for the page number and then add the buttons to the paginationNumbers
container.
const appendPageNumber = (index) => { const pageNumber = document.createElement("button"); pageNumber.className = "pagination-number"; pageNumber.innerHTML = index; pageNumber.setAttribute("page-index", index); pageNumber.setAttribute("aria-label", "Page " + index); paginationNumbers.appendChild(pageNumber); }; const getPaginationNumbers = () => { for (let i = 1; i <= pageCount; i++) { appendPageNumber(i); } };
And then we’ll call the getPaginationNumbers
function when the web page loads using the window.load()
event:
window.addEventListener("load", () => { getPaginationNumbers(); });
Display Active Page
We want to define a function to only display as many items are allowed in the paginationLimit
on each page. Here’s how we’ll implement it:
Set the value of the currentPage
variable to the pageNum
value:
const setCurrentPage = (pageNum) => { currentPage = pageNum; };
Get the range for items to be shown. If we’re on page 1, we want to show items 1 to 10 (according to the paginationLimit
). if we’re on page 2, we want to show items 11 to 20 and so on.
const setCurrentPage = (pageNum) => { currentPage = pageNum; const prevRange = (pageNum - 1) * paginationLimit; const currRange = pageNum * paginationLimit; };
Loop through the list of items to be displayed and hide all the items. Then unhide all the items that fall within the range.
Note: since we’re working with arrays, item 1 will be at 0 and item 10 will be at position 9 so our logic looks like this:
const setCurrentPage = (pageNum) => { currentPage = pageNum; const prevRange = (pageNum - 1) * paginationLimit; const currRange = pageNum * paginationLimit; listItems.forEach((item, index) => { item.classList.add("hidden"); if (index >= prevRange && index < currRange) { item.classList.remove("hidden"); } }); };
We use this method since our implementation is just hiding HTML content. If we were trying to append content from a JSON object to the DOM, we could update the logic to look something like:
jsonData.forEach((item, index) => { elementContainer.innerHTML = '' if (index >= prevRange && index < currRange) { elementContainer.appendChild(item) } });
Update the window.load()
event to set the current page as page 1 once the webpage loads:
window.addEventListener("load", () => { getPaginationNumbers(); setCurrentPage(1); });
Add Page Number Buttons Event Listener
Use a click event listener to trigger the setCurrentPage
function whenever a page number button is clicked. Place this function inside the window.load()
event so now the function looks like this:
window.addEventListener("load", () => { getPaginationNumbers(); setCurrentPage(1); document.querySelectorAll(".pagination-number").forEach((button) => { const pageIndex = Number(button.getAttribute("page-index")); if (pageIndex) { button.addEventListener("click", () => { setCurrentPage(pageIndex); }); } }); });
Set Active Page Number
We also want to define a function to add the active class to the page number we just clicked. We reset all buttons on the page by removing the active class. Then, if the page-index of the button matches the currentPage
global variable, we add the active class to that button.
const handleActivePageNumber = () => { document.querySelectorAll(".pagination-number").forEach((button) => { button.classList.remove("active"); const pageIndex = Number(button.getAttribute("page-index")); if (pageIndex == currentPage) { button.classList.add("active"); } }); };
Include this function in the setCurrentPage
function so the active page number is updated every time a new page is set:
const setCurrentPage = (pageNum) => { currentPage = pageNum; handleActivePageNumber(); const prevRange = (pageNum - 1) * paginationLimit; const currRange = pageNum * paginationLimit; listItems.forEach((item, index) => { item.classList.add("hidden"); if (index >= prevRange && index < currRange) { item.classList.remove("hidden"); } }); };
At this point, we should have a functional Page navigation system that looks like this:
Next and Previous Buttons
Let’s extend this functionality to include the next and previous buttons. We can use the same implementation in the setCurrentPage()
function, and update the logic:
- for the previous button, we change the page using
setCurrentPage(currentPage - 1)
- for the next button, we change the page using
setCurrentPage(currentPage + 1)
Include the event listeners for next and previous buttons in window.load()
:
window.addEventListener("load", () => { getPaginationNumbers(); setCurrentPage(1); prevButton.addEventListener("click", () => { setCurrentPage(currentPage - 1); }); nextButton.addEventListener("click", () => { setCurrentPage(currentPage + 1); }); document.querySelectorAll(".pagination-number").forEach((button) => { const pageIndex = Number(button.getAttribute("page-index")); if (pageIndex) { button.addEventListener("click", () => { setCurrentPage(pageIndex); }); } }); });
Disable Page Navigation Buttons
We also want to include a disabling feature on the next and previous buttons.
- disable the previous button if we’re on the first page (if current page is 1)
- disable the next button if we’re on the last page (if current page is total number of pages)
const disableButton = (button) => { button.classList.add("disabled"); button.setAttribute("disabled", true); }; const enableButton = (button) => { button.classList.remove("disabled"); button.removeAttribute("disabled"); }; const handlePageButtonsStatus = () => { if (currentPage === 1) { disableButton(prevButton); } else { enableButton(prevButton); } if (pageCount === currentPage) { disableButton(nextButton); } else { enableButton(nextButton); } };
Finally, pass the handlePageButtonsStatus()
function into the setCurrentPage()
function so we check the navigation every time a new page is clicked:
const setCurrentPage = (pageNum) => { currentPage = pageNum; handleActivePageNumber(); handlePageButtonsStatus(); const prevRange = (pageNum - 1) * paginationLimit; const currRange = pageNum * paginationLimit; listItems.forEach((item, index) => { item.classList.add("hidden"); if (index >= prevRange && index < currRange) { item.classList.remove("hidden"); } }); };
Conclusion
And that’s all folks! We now have a fully functional and accessible implementation of a paginated section.
Level up Your Front End JavaScript Skills!
We have loads of great foundational and practical JavaScript tutorials on Tuts+, so you can learn as you create: