Introduction
When creating a website or web application, especially if they feature a lot of templated content (such as a grid or list of items belonging to a category) - it's generally a good idea to divide it into pages to reduce the number of items that appear on the screen at once.
In this article, we will learn how to implement pagination in our web projects using vanilla JavaScript from the ground up.
For the purpose of this article, we will fetch the content from this example API response. It contains 100 data points, but we'll only use 30 and display 6 posts on our screen at a time.
Getting Started
Before fetching all required posts from the API using the browsers built-in Fetch API, we first need to create a basic HTML markup that will be dynamically filled via our script later:
<div class="container">
<div class="title-section">
<h1 class="title">Posts</h1>
</div>
<div class="posts-section"></div>
<div class="pagination-section">
<ul class="pagination">
<li class="page-item prev"><a class="page-link" href="#">Previous</a></li>
<li class="page-item next"><a class="page-link" href="#">Next</a></li>
</ul>
</div>
</div>
Fetching REST API Posts
As mentioned before, pagination is all about splitting up content into smaller chunks. It requires you to fetch the data, decide when and how to split, calculate the number of pages, and then show a portion of it to the user. Thankfully - back-end functionality usually takes care of the first few tasks, and return the relevant page, total number of pages, and the content per page.
Note: Depending on the specific API you're working with - you may or may not be able to lazy load results. Whenever possible - prefer lazy loading results instead of loading them all upfront. Most modern APIs follow practices that let you set a limit
or page
count, and return the total number of pages that you can display to the user.
Let's get started by first fetching all our posts and then later we will amend this to query only a few data points per page:
const postsSection = document.querySelector(".posts-section");
const fetchPosts = async () => {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts"
);
const posts = await response.json();
postsSection.innerHTML = "";
posts.forEach((post) => {
postsSection.innerHTML += `
<div class="posts-card">
<div class="post-title">
<h2 class="post-title-text">${post.title}</h2>
</div>
<div class="post-body">
<p class="post-body-text">
${post.body}
</p>
</div>
</div>
`;
});
};
fetchPosts();
Let's quickly examine the code above. First of all, we began by obtaining the div
element where we would be displaying all of our content via the class
name we assigned to the div
. Finally, we wrote a function to handle the fetch operation.
In the fetchPosts()
function, we used the Fetch API to retrieve posts from the JSON Placeholder posts API, then store the JSON data referenced by the posts
variable and used the innerHTML
property to add each piece of content to the posts-section
by looping through them.
At this point, we have successfully fetched all of our content.
Note: You can also fetch the content using a different method, but make sure that all of your content is loaded on that page before we dive into creating the pagination.
How to Implement Pagination in JavaScript
Let's begin by declaring three variables that are critical for implementing pagination within our web page. The first one is the number of posts we want to declare per page, then the current page number (1
by default), and the total number of pages.
Note: When consuming data from a standard API and database, the total count of the pages or the data points is usually returned. If we don't receive a total page count, it can be calculated via the total object count and the page size.
For this guide we will give the total number of pages a fixed number of 30
:
const numberPerPage = 6;
var pageNumber = 1;
var numberOfPages = 30;
In the previous section, we've displayed all posts on a single page, but we want to show only six at a time. Therefore, we've set the numberPerPage
to 6
which we will now use to adjust the fetch operation so it only displays 6
posts.
It depends on the specific implementation, but it's wide-spread practice to allow query parameters to be used when fetching results from APIs, that allow you to fetch a certain page of the results. For example the mock REST API that we're using allows for the page
and limit
parameters that let you only load batches that you'll show at a given time.
This way, we only load the data we want to show to the user! We can then either pre-fetch the next page for faster loading time, or revel in the computational speedup achieved by only loading the data to be shown.
We'll be making use of these parameters by amending our fetch request:
const fetchPosts = async (pageNumber) => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_page=${pageNumber}&_limit=${numberPerPage}`
);
const posts = await response.json();
postsSection.innerHTML = "";
posts.forEach((post) => {
postsSection.innerHTML += `
<div class="posts-card">
<div class="post-title">
<h2 class="post-title-text">${post.title}</h2>
</div>
<div class="post-body">
<p class="post-body-text">
${post.body}
</p>
</div>
</div>
`;
});
};
fetchPosts();
In the above code, we added the two parameters to the API endpoint which are the pageNumber
and the number of posts per page which would help us break our posts into several pages and then these posts can now be displayed based on the page number.
Additionally, we also passed in the pageNumber
to the fetchPosts()
function so we can call this function whenever the page changes:
Let's now add functionality to the page navigation buttons at the bottom of our page and have them display appropriate content based on the page number.
Implementing Pagination Logic
We will notice that in the markup we had a section that showing the pagination buttons:
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
<div class="pagination-section">
<ul class="pagination">
<li class="page-item prev"><a class="page-link" href="#">Previous</a></li>
<li class="page-item next"><a class="page-link" href="#">Next</a></li>
</ul>
</div>
We are now going to add click
events to each button so that when they are clicked, the content intended for that page appears.
Implementing the Previous Button
The logic here is pretty simple. All we have to do is to retrieve the element representing the previous button, add the click
event listener to it and show the appropriate content when the button is clicked:
// Add event listeners to the prev button
const prev = document.querySelector('.prev');
prev.addEventListener('click', (e) => {
e.preventDefault();
if (pageNumber > 1) {
pageNumber--;
fetchPosts(pageNumber);
}
});
After adding a click
event listener, we've checked if the current page number is greater than 1
in the call back function. If the number is equal to or less than 1
, we'll just keep showing the current content. But if the current page number is greater than 1
we can freely decrement its value and call the fetchPosts(pageNumber)
function with the new page number passed in it as an argument, therefore showing the content of the previous page.
Implementing the Next Button
The logic here is completely the same as for the previous button, with just a few minor changes. Of course, we'll retrieve the list element with the class next
instead of prev
. Also, we'll check whether the current page number is less than the number of pages which we set to 30
manually earlier. In the end, we'll increment the current page number instead of decrementing it:
// Add event listeners to the next button
const next = document.querySelector(".next");
next.addEventListener("click", (e) => {
e.preventDefault();
if (pageNumber < numberOfPages) {
pageNumber++;
fetchPosts(pageNumber);
}
});
Conclusion
Splitting content into smaller, more manageable chunks that are displayed individually is crucial whenever you try to display a database or any other data source on your web application.
In this article, we took a look at how to implement pagination with JavaScript from scratch, without any external libraries and tools.