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:
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 orcommand prompt
and navigate to the present directory. - Create React App by running
npx create-react-app .
to setup React in the current directory ornpx create-react-app app-name
to create a new folder calledapp-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
insrc
- Create
Table.js
andPagination.js
in theComponents
directory. - Create a new folder:
variables
insrc
- Create
data.js
in thevariables
directory and add this array found here .
Create the components and import appropriately.
- Create a functional component in
Table.js
andPagination.js
- Import
Pagination
intoTable.js
and returnPagination
component as JSX. - Import
Table
intoApp.js
and returnTable
component as JSX.
The app and file will look something like this:
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 ofpages-container
- Inside the
ul
returnli
with class ofpage-item
and anonClick
eventListener.<li className="page-item" onClick={prevHandler}> Prev </li>
- Create an array with the pages props and return
li
elements. Theli
will check the page and if the page is selected, will add an active class. TheonClick
passed as a prop will be taken care of in theTable.js
. Also, an array will be created with the the value of pages which is essentially a number.
- An enclosing
{[...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 ofpage-item
and anonClick
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 Pagination
and 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
andthePageLength
variables. if the page is less than thepageLength
, 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
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