reCAPTCHA WAF Session Token
Programming Languages

How to Implement Pagination with HTML, CSS and JavaScript

On the Web, pagination is a way to break up large pieces of content into more bite-sized pieces. In this article, we’ll look at a simple way to divide content into a series of “pages” using HTML, CSS and vanilla JavaScript.

Although pagination can be implemented using frameworks such as React and Angular, the aim of this article is to provide a straightforward, step-by-step guide to setting up pagination, so that we can understand the basic concepts involved.

Table of Contents
  1. Creating Our Base Web Page
  2. Implementing the Pagination Functionality with JavaScript
  3. Adapting Our Code to Other Scenarios
  4. Conclusion

Creating Our Base Web Page

Before implementing our pagination system, let’s create an HTML structure that stores the content we want to display. This can be any kind of content, but for this tutorial, we’ll use a table of five columns and 15 rows that stores the names of students in different grades. Here’s a snippet of our HTML:

<article class="content">
  <table>
    <thead>
      <tr>
        <th>Grade 1</th>
        <th>Grade 2</th>
        <th>Grade 3</th>
        <th>Grade 4</th>
        <th>Grade 5</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Faith Andrew</td>
        <td>Angela Christopher`</td>
        <td>David Elias</td>
        <td>Samuel Thomas</td>
        <td>Richard Elias</td>
      </tr></tbody>
  </table>
</article>

We’ve wrapped the table in a container element (<article class="content">). While we don’t strictly need a container element, it’s handy to have it, especially if there are other elements on our page. (It gives a useful context for the pagination buttons that we’ll be adding.)

You can view our full HTML code, along with some styling, on CodePen.

With our HTML and CSS in place, the next step is to implement pagination. We’ll firstly use JavaScript to divide the table into different “pages” and to add button functionality for navigating through those pages.

Creating a function that divides the table into pages

Here’s our code for dividing the table into separate pieces:

document.addEventListener('DOMContentLoaded', function () {
  const content = document.querySelector('.content'); 
  const itemsPerPage = 5;
  let currentPage = 0;
  const items = Array.from(content.getElementsByTagName('tr')).slice(1);

The first line creates an event listener that ensures that the JavaScript code runs after the HTML content has been fully loaded and parsed. This is to prevent any manipulation or interaction with elements before the content becomes available in the DOM.

With document.querySelector('.content'), we’re selecting the <article class="content"> wrapper and initializing it as a variable.

With const itemsPerPage = 5;, we’re setting the number of rows to display on each page.

With let currentPage = 0;, we’re creating a variable that keeps track of the current page number. It starts at 0, which represents the first page. (The first index in JavaScript is 0, so it counts from 0 instead of 1.)

The last line uses the getElementsByTagName method to select all the elements with a <tr> tag within the table. We create an array (items) of all the child elements and used the slice(1) to exclude the first row (header) and create an array of the remaining rows.

This means that the heading will remain in place as we switch pages.

Working out the showPage() functionality

Next, let’s work on the code for showing pages:

function showPage(page) {
  const startIndex = page * itemsPerPage;
  const endIndex = startIndex + itemsPerPage;
  items.forEach((item, index) => {
    item.classList.toggle('hidden', index < startIndex || index >= endIndex);
  });
  updateActiveButtonStates();
}

We start by creating a showPage() function that accepts a page parameter. This function is responsible for displaying the items connected to that specific page when it’s called.

Next, we calculate the startIndex, which is the first item that should be displayed on the current page by multiplying the page parameter with the itemsPerPage. We also calculate the endIndex that comes immediately after the last item that should be displayed on the current page.

By doing this, we’re creating a range of items to be displayed. For example, let’s say we have ten items and we want to display five items per page. If we’re on the first page (page = 0), startIndex will be 0, and endIndex will be 0 + 5 = 5. This range ([0, 5]) includes the first five items. On the next page (page = 1), startIndex will be 5, and endIndex will be 5 + 5 = 10. This range ([5, 10]) includes the remaining items.

With items.forEach(), we create a loop that iterates through each row and checks if its index falls within the range of items to be displayed on the current page — that is, if it’s either before the startIndex or after/equal to the endIndex. If the index is within the range, the toggle keyword applies the hidden class (which we’ll define in our CSS code) to the item, effectively hiding it. If the index doesn’t meet either condition, the hidden class is removed, making the item visible.

Our hidden class moves the items off screen, hiding them from view but still allowing them to be accessible to those using screen readers:

.hidden {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

Adding buttons

Let’s now look at how to add our navigation buttons. In the code below, we’ll create and add the button functionality based on the content of the table:

function createPageButtons() {
  const totalPages = Math.ceil(items.length / itemsPerPage);
  const paginationContainer = document.createElement('div');
  const paginationDiv = document.body.appendChild(paginationContainer);
  paginationContainer.classList.add('pagination');

Firstly, we create a createPageButtons() function that will store the logic to create our buttons. Then we calculate the total pages we’ll need to display our table. We do this by dividing the total number of items by the desired number of items per page. The result is rounded up using the Math.ceil() function. This ensures that all the rows of our table items are covered by the available pages.

Next, we create a div to contain our dynamically generated page buttons (document.createElement('div')). Then we appended the <div> element to the body of our HTML structure using document.body.appendChild(paginationDiv). (We haven’t actually told it where to sit in the HTML structure yes. We’ll do that shortly.) Lastly, we add a class of pagination to that button container so that we can target it with styles.

The next step is to create buttons for each page, using a loop to iterate through each possible page index:

for (let i = 0; i < totalPages; i++) {
const pageButton = document.createElement('button');
pageButton.textContent = i + 1;
pageButton.addEventListener('click', () => {
  currentPage = i;
  showPage(currentPage);
  updateActiveButtonStates();
});

The for loop ranges from 0 (which is the first page) to the total number of pages minus 1.

Within each page iteration, a new individual page button is created using the document.createElement() method, increasing the page number by 1 each time it loops.

Next, we create a click event listener and attach it to the page buttons. When a button is clicked, the event listener’s callback function gets executed.

Here’s an explanation of the callback function:

  • The currentPage variable is updated to the current value of i, which corresponds to the index of the clicked page.
  • The showPage() function is called with the updated currentPage value, causing the content of the clicked page to be displayed.

To finish off our button creation code, we end with this:

content.appendChild(paginationContainer);
paginationDiv.appendChild(pageButton);

We append our button container to the end of our .content wrapper, and then place our buttons inside the button container.

Highlighting active buttons

To make our buttons more user-friendly, we’ll add a distinctive style to the currently “active” button. Let’s create a function that applies the styles of the active CSS class to a button once its page is active:

function updateActiveButtonStates() {
  const pageButtons = document.querySelectorAll('.pagination button');
  pageButtons.forEach((button, index) => {
    if (index === currentPage) {
      button.classList.add('active');
    } else {
      button.classList.remove('active');
    }
  });
}

First, we retrieve all the pagination buttons using the document.querySelectorAll and assign them to the pageButtons variable.

The updateActiveButtonStates() function then goes through each of these buttons one by one, using a forEach loop, and compares its index with the value of the currentPage variable.

Next, we use the conditional if statement to assign the styles of the active class if the button’s index matches the current page.

If the button’s index doesn’t match the current page, the active class is removed. This ensures that the other buttons don’t retain the active class.

To implement this feature, we call the updateActiveButtonStates() function whenever a page is changed or displayed.

Calling on the script

Our pagination script ends with the following two lines:

createPageButtons();
showPage(currentPage);

We call the createPageButtons() function before the showPage() function. This ensures that the buttons are created once the page loads.

Our script now calculates the appropriate range of items to display for each page, listens for button clicks, and updates the page display.

The final result

The following Pen shows the final result.

Adapting Our Code to Other Scenarios

The script we’ve created is handy for breaking up a table into a series of pages. But what if our content is something other than a table? Instead of table content, let’s try our script with some other kinds of content.

Instead of a table element, let’s place some <section> elements inside our container and see how to adapt our script. Here’s our basic HTML:

<article class="content">
  <section></section>
  <section></section>
  <section></section>
  <section></section>
  <section></section>
</article>

We only need to make three very simple changes to our script:

document.addEventListener('DOMContentLoaded', function () {
const content = document.querySelector('.content'); 
const itemsPerPage = 1;
let currentPage = 0;
const items = Array.from(content.getElementsByTagName('section')).slice(0);

The changes are:

  • set itemsPerPage to 1, so that only one section appears per page
  • change the targeted tag name to section, as we’re now looping through <section> elements rather than <tr> elements
  • set slice() to 0, which limits the selection to the first section element (which has index 0)

The following CodePen demo shows this in action.

We can easily adapt the demo above to work with a list of items. In the example below, we change the wrapping element from an <article> to a <ul>, and change the <section> elements to <li> elements:

<ul class="content">
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

In our JavaScript, we’ll just make two changes:

  • getElementsByTagName('section') becomes getElementsByTagName('li')
  • let’s set const itemsPerPage to 2 to show two list items per page

After some minor CSS changes to account for the unordered list, we end up with the result below.

Conclusion

In this tutorial, we learned how to implement pagination using HTML, CSS and JavaScript. For those without JavaScript enabled (for whatever reason), the full content is still available — just without pagination. By using semantic <button> elements, the page is still keyboard accessible. We’ve also hidden our non-active content by moving it off screen, rather than using display: none, so that it’s still accessible to screen readers.

We could go further by adding descriptive ARIA labels and attributes to convey the purpose and role of elements such as pagination buttons to screen readers.

I hope this demo will get you thinking about simple pagination functionality without needing to reach for a framework.




Source link

Leave a Reply

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

Back to top button
WP Twitter Auto Publish Powered By : XYZScripts.com
SiteLock Consent Preferences

Adblock Detected

Please consider supporting us by disabling your ad blocker