Pagination in ReactJS without a CSS Framework

Pagination in ReactJS without a CSS Framework

Pagination groups large amount of data into smaller sets and helps user navigate in an orderly manner. In this article, we will create it from scratch

Pagination

Pagination is the sequence of numbers assigned to pages in a website. They help group a large amount of data or response into smaller groups. This grouping enables the user or viewer understand and navigate through the data in an orderly manner.

Pagination can be achieved using a CSS framework such as BootstrapCSS or packages such as react-paginate. However, nothing beats creating the logic yourself and knowing how it works under the hood. This gives you the advantage of customization and knowledge expansion. It enables you understand better how to use functions, props and state (useState) in ReactJS.

Pagination Demo

In this article we will create a pagination functionality without any external package and what we will be creating is shown in the demo below:

demo.gif

Creating The Project Skeleton

To create the project skeleton, you can clone the starter files here or you can follow the instructions below.

Initialize React App

  • Create a new folder on your computer and open it in a code editor such as VS code.
  • Open your terminal present in VS code or command prompt and navigate to the present directory.
  • Create React App by running npx create-react-app . to setup React in the current directory or npx create-react-app app-name to create a new folder called app-name and setup React in it.

Clean up the default App

  • Clear up App.js and export a default App Component.
import React from 'react'

const App = () => {
  return (
    <div className="app">

    </div>
  )
}

export default App
  • Clear up index.css and leave it blank.

Setup File Structure

  • Create a new folder: Components in src
  • Create Table.js and Pagination.js in the Components directory.
  • Create a new folder: variables in src
  • Create data.js in the variables directory and add this array found here .

Create the components and import appropriately.

  • Create a functional component in Table.js and Pagination.js
  • Import Pagination into Table.js and return Pagination component as JSX.
  • Import Table into App.js and return Table component as JSX.

The app and file will look something like this:

structure.PNG

Build the Table Component

To build the Table component do the following:

  • Import necessary files.
import React, { useState } from "react";
import { football } from "../variables/data";
import Pagination from "./Pagination";
  • Setup the state and variables
  const pageSize = 5;
  const pageLength = football.length / pageSize;
  const [page, setPage] = useState(1);
  const [list, setList] = useState(football.slice(page - 1, page * pageSize));
  • Build the Table JSX

Here, we return a div element with a table-container class. Inside the div element we nest a table element with table class.

Inside the table we return caption with the text Pagination in ReactJS without a CSS Framework in it.

Below the caption, add a thead element. Inside the thead add a tr and inside tr nest three th elements.

  <caption>Pagination in ReactJS without a CSS Framework</caption>

      <tr>
            <th>Long</th>
            <th className="center">Short</th>
            <th>Country</th>
          </tr>

Below the thead, add a tbody element. Loop through the list variable using the map (higher order function) to return a tr and three td elements nested in it like:

      <tbody>
          {list.map((x, i) => {
            const { long, short, country } = x;
            return (
              <tr key={i}>
                <td>{long}</td>
                <td className="center">{short}</td>
                <td>{country}</td>
              </tr>
            );
          })}
        </tbody>

The already completed file will look like:

import React, { useState } from "react";
import { football } from "../variables/data";
import Pagination from "./Pagination";

const Table = () => {
  const pageSize = 5;
  const pageLength = football.length / pageSize;
  const [page, setPage] = useState(1);
  const [list, setList] = useState(football.slice(page - 1, page * pageSize));

  return (
    <div className="table-container">
      <table className="table">
        <caption>Pagination in ReactJS without a CSS Framework</caption>
        <thead>
          <tr>
            <th>Long</th>
            <th className="center">Short</th>
            <th>Country</th>
          </tr>
        </thead>
        <tbody>
          {list.map((x, i) => {
            const { long, short, country } = x;
            return (
              <tr key={i}>
                <td>{long}</td>
                <td className="center">{short}</td>
                <td>{country}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

export default Table;

Build the Pagination Component

  • Pass the appropriate props such as page, pages, onClick, prevHandler, nextHandler

  • Return pagination JSX

    • An enclosing div
    • ul element with the class of pages-container
    • Inside the ul return li with class of page-item and an onClick eventListener.
      <li className="page-item" onClick={prevHandler}>
            Prev
      </li>
      
    • Create an array with the pages props and return li elements. The li will check the page and if the page is selected, will add an active class. The onClick passed as a prop will be taken care of in the Table.js. Also, an array will be created with the the value of pages which is essentially a number.
      {[...Array(Math.ceil(pages)).keys()].map((x, i) => {
          return (
            <li
              key={i}
              className={page - 1 === i ? "active page-item" : "page-item"}
              onClick={(e) => onClick(e.target.innerText)}
            >
              {x + 1}
            </li>
          );
        })}
  • Another li with class of page-item and an onClick event.

The already completed file will look like:

import React from "react";

const Pagination = ({ page, pages, onClick, prevHandler, nextHandler }) => {
  return (
    <div>
      <ul className="pages-container">
        <li className="page-item" onClick={prevHandler}>
          Prev
        </li>

        {[...Array(Math.ceil(pages)).keys()].map((x, i) => {
          return (
            <li
              key={i}
              className={page - 1 === i ? "active page-item" : "page-item"}
              onClick={(e) => onClick(e.target.innerText)}
            >
              {x + 1}
            </li>
          );
        })}

        <li className="page-item" onClick={nextHandler}>
          Next
        </li>
      </ul>
    </div>
  );
};

export default Pagination;

Add the appropriate styles

Attach the following file in the style.css:

html {
  box-sizing: border-box;
}

body {
  margin: 0;
  background-color: black;
}

*,
*::before,
*::after {
  padding: 0;
}

.app {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-top: 5rem;
}
.table-container {
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-shadow: 0 0 5px rgba(0, 0, 255, 0.274);
  background-color: rgb(38, 222, 246);
  border-radius: 10px;
}
.table {
  margin: 1.5rem;
  width: 80%;
  color: rgb(0, 0, 0);
}
.table th {
  text-align: left;
}
th {
  padding-bottom: 1rem;
  font-size: 1.1rem;
}
td {
  border-top: 1px solid rgba(0, 0, 0, 0.096);
  padding: 0.7rem 0;
}

.table .center {
  padding-left: 1rem;
  padding-right: 1rem;
}
caption {
  font-size: 1.4rem;
  margin-bottom: 1.3rem;
  color: rgb(0, 0, 0);
  font-weight: 600;
}
.pages-container {
  display: flex;
  list-style: none;
}

.page-item {
  padding: 0.5rem;
  cursor: pointer;
  border: 1px solid rgba(0, 0, 0, 0.205);
  margin-right: 0.25rem;
}

.page-item:hover {
  background-color: rgba(0, 0, 0, 0.329);
  color: white;
}

.page-item.active {
  transform: scale(1.1);
  background-color: rgba(0, 0, 0, 0.801);
  color: white;
}

Combine Pagination and Table component

Create handlePage function

The handlePage function handles the pagination by clicking on the number buttons. It accepts thePage parameter and performs the appropriate logic to change the list returned.

  const handlePage = (thePage) => {
    setPage(thePage);
    const t = football.slice((thePage - 1) * pageSize, thePage * pageSize);
    setList(t);
  };

Add Pagination Component

Here we will import the Paginationand use it below the table element.

We pass the page, pages and onClick with page state, pageLength variable and the just created handlePage function. The handlePage function uses the parameter passed from the Pagination.js onClick function.

      <Pagination
        page={page}
        pages={pageLength}
        onClick={(pageEvent) => {
          handlePage(pageEvent);
        }}
      />

Handle the Next and Previous Functionality

  • prevHandler function: This function accepts thePage parameter. it checks for when the page is equal to the first page and does nothing, else it decrements the page by one.
  const prevHandler = (thePage) => {
    if (thePage === 1) {
      handlePage(1);
    } else {
      handlePage(Number(thePage) - 1);
    }
  };
  • nextHandler function: This function accepts thePage and thePageLength variables. if the page is less than the pageLength, it increments the page by one, else it does nothing.
  const nextHandler = (thePage, thePageLength) => {
    if (thePage < thePageLength) {
      handlePage(Number(thePage) + 1);
    }
  };
  • Pass the function into the Pagination component as props
      <Pagination
        page={page}
        pages={pageLength}
        onClick={(pageEvent) => {
          handlePage(pageEvent);
        }}
        prevHandler={() => prevHandler(page)}
        nextHandler={() => nextHandler(page, pageLength)}
      />

Final Result will should look like this:

The source code can be found here on github demo.gif

Conclusion

To conclude, I want you to know that you have successfully built a Pagination functionality that you can use in your projects. You can also expand it to have more features.

Support me

author: Onuorah Bonaventure Chukwudi

Patreon: Bonarhyme Tech Hub

twitter: https://twitter.com/bonarhyme

blog: https://blog.bonarhyme.com

youtube: Bonarhyme Tech Hub