# Build a Custom Pagination Component in ReactJS from Scratch

> Learn how to build a custom pagination component in ReactJS from scratch. Follow this step-by-step guide to integrate Pagination component in your ReactJS project.

- **Source:** DevDreaming (https://devdreaming.com)
- **Canonical URL:** https://devdreaming.com/blogs/create-pagination-component-reactjs
- **Author:** CodeBucks
- **Published:** 2021-01-04
- **Last updated:** 2023-01-01
- **Topics:** React js, User Experience

---

Hello there👋,

Hope you all doing great. In this post we're going build a pagination component from scratch in [React.js](/videos/category/react-js). We're not going to use any library here. If you prefer to watch video then you can go to the following video else keep reading...😄

[▶ Watch the video on YouTube](https://www.youtube.com/watch?v=6DtBw3PaeHs)

### Setting Up The Project And Pagination Component

Let's start by creating the react-app using following command,

```powershell
npx create-react-app react-pagination-component
```

Create a separate file called `PaginationComponent.js` . Here, We will use [jsonplaceholder API](https://jsonplaceholder.typicode.com/guide/) to get data and use pagination on that data. This API will return us a list of todos. Now to store this data let's create one state and initialize it with an empty array.

```javascript
const [data, setData] = useState([]);
```

Now let's use `useEffect` to set this state with our data which comes from API.

```javascript
useEffect(() => {
  fetch("https://jsonplaceholder.typicode.com/todos")
    .then((response) => response.json())
    .then((json) => setData(json));
}, []);
```

if you want to see what type of data this api is providing then just go to this url:[API](https://jsonplaceholder.typicode.com/todos). Also if you don't know how to fetch api in ReactJS then you can watch my video on How to [fetch API](https://youtu.be/27f3B1qndW8). let's create small `renderData` function outside of our main component to render todo list.

```javascript
import React, { useEffect, useState } from "react";
import "./style.css";

const renderData = (data) => {
  return (

    <ul>
      {data.map((todo, index) => {
        return <li key={index}>{todo.title}</li>;
      })}
    </ul>

  );
};

function PaginationComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {

    fetch("https://jsonplaceholder.typicode.com/todos")
      .then((response) => response.json())
      .then((json) => setData(json));

  }, []);

  return (

    <>
      <h1>Todo List</h1> <br />
      {renderData(data)}

    </>

  );
}

export default PaginationComponent;
```

**Line no 4 to 12:** Here, We have mapped title of to-dos from data state.

**Line no 26:** Let's Render `renderData(data)` with data state.

### Building the logic for pagination

Let's create two states in `PaginationComponent.js` file.

```javascript
const [currentPage, setcurrentPage] = useState(1);
const [itemsPerPage, setitemsPerPage] = useState(5);
```

- `currentPage:` It stores current page number, initially 0.
- `itemsPerPage:` It stores no of items we want to display in single page. Initially it is 5.

```javascript
const pages = [];
for (let i = 1; i <= Math.ceil(data.length / itemsPerPage); i++) {
  pages.push(i);
}
```

In above code, pages array contains total number of pages like 1, 2, 3..upto `(total data / itemsPerPage)` . If you have 20 items and you want to display 5 items per page then you will need 20/5 = 4 pages. Let's create `renderPageNumbers` function which will display page numbers.

```javascript
import React, { useEffect, useState } from "react";
import "./style.css";

const renderData = (data) => {
  return (

    <ul>
      {data.map((todo, index) => {
        return <li key={index}>{todo.title}</li>;
      })}
    </ul>

  );
};

function PaginationComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {

    fetch("https://jsonplaceholder.typicode.com/todos")
      .then((response) => response.json())
      .then((json) => setData(json));

  }, []);

  const handleClick = (event) => {

    setcurrentPage(Number(event.target.id));

  };

  const renderPageNumbers = pages.map((number) => {

    return (
      <li
        key={number}
        id={number}
        onClick={handleClick}
        className={currentPage == number ? "active" : null}
      >
        {number}
      </li>
    );

  });

  return (

    <>
      <h1>Todo List</h1> <br />
      {renderData(data)}

      <ul className="pageNumbers">
        {renderPageNumbers}
      </ul>

    </>

  );
}

export default PaginationComponent;
```

**Line no 27 to 39:** Here, we have mapped this pages array which will return an `li` tag which display page numbers. This `li` tag contains key, id, `onClick` method and `className`. Here, the `className` becomes `active` when you are on the same page as `currentPage` state.

**Line no 23:** This `handleClick` method runs when we click on any page number and set `currentPage` state to selected page number.

**Line 47:** Here, we have Rendered `renderPageNumbers` component by wrapping it with `ul` tag and `className` as `pageNumbers`.

> **Note:**
>
>  For styling, you can refer
>
> [pagination css](https://github.com/codebucks27/react-pagination-component/blob/main/src/components/style.css)
>
>  css file.

As you have observed, This page numbers are all over the whole page and now we need to set limit to display this page numbers. To do that we need to define 3 more React states.

```javascript
const [pageNumberLimit, setpageNumberLimit] = useState(5);
const [maxPageNumberLimit, setmaxPageNumberLimit] = useState(5);
const [minPageNumberLimit, setminPageNumberLimit] = useState(0);
```

- `pageNumberLimit:` It is to store how many page numbers you want to display. Here I want to display only 5.
- `maxPageNumberLimit:` It is to store max page bound limit.
- `minPageNumberLimit:` It is to store min page bound limit.

Now let's modify `renderPageNumbers` component by putting `if` condition like given below,

```javascript
const renderPageNumbers = pages.map((number) => {
  if (number < maxPageNumberLimit + 1 && number > minPageNumberLimit) {
    return (
      <li
        key={number}
        id={number}
        onClick={handleClick}
        className={currentPage == number ? "active" : null}
      >
        {number}
      </li>
    );
  } else {
    return null;
  }
});
```

This `if` condition means that if current number is greater then `maxPageNumberLimit+1` and less then `minPageNumberLimit` then render it else render nothing. As you run your code, you will see that there are only 5 page numbers displayed. Next we need `next` and `previous` buttons. Create those buttons around the `{renderPageNumbers}` component as in the following code block,

```javascript
import React, { useEffect, useState } from "react";
import "./style.css";

const renderData = (data) => {
  return (

    <ul>
      {data.map((todo, index) => {
        return <li key={index}>{todo.title}</li>;
      })}
    </ul>

  );
};

function PaginationComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {

    fetch("https://jsonplaceholder.typicode.com/todos")
      .then((response) => response.json())
      .then((json) => setData(json));

  }, []);

  const handleClick = (event) => {

    setcurrentPage(Number(event.target.id));

  };

   const renderPageNumbers = pages.map((number) => {

      return (
        <li
          key={number}
          id={number}
          onClick={handleClick}
          className={currentPage == number ? "active" : null}
        >
          {number}
        </li>
      );

  });

    const handleNextbtn = () => {
    setcurrentPage(currentPage + 1);

    if (currentPage + 1 > maxPageNumberLimit) {
      setmaxPageNumberLimit(maxPageNumberLimit + pageNumberLimit);
      setminPageNumberLimit(minPageNumberLimit + pageNumberLimit);
    }

  };

  const handlePrevbtn = () => {

    setcurrentPage(currentPage - 1);

    if ((currentPage - 1) % pageNumberLimit == 0) {
      setmaxPageNumberLimit(maxPageNumberLimit - pageNumberLimit);
      setminPageNumberLimit(minPageNumberLimit - pageNumberLimit);
    }

  };

  return (

    <>
      <h1>Todo List</h1> <br />
      {renderData(data)}

      <ul className="pageNumbers">
        <li>
          <button
            onClick={handlePrevbtn}
            disabled={currentPage == pages[0] ? true : false}
          >
            Prev
          </button>
        </li>
        {renderPageNumbers}
        <li>
          <button
            onClick={handleNextbtn}
            disabled={currentPage == pages[pages.length - 1] ? true : false}
          >
            Next
          </button>
        </li>
      </ul>

    </>

  );
}

export default PaginationComponent;
```

**Line no 66-73 and 75-81:**
There are two buttons prev and next.

**Line 41:** Here, the `handleNextbtn` method is for the next button. In this method whenever user clicks on `next` button, it will set the `currentPage` state to plus 1 and check the condition whether the current page has crossed maximum page number limit or not. If yes then it will reset this max and min page number limit with new limit.

**Line 50:** Here is the method for previous button. Only change is in the sign and in the if condition. Suppose you are at page 6 and you want to go back to 5 then this condition will check that 6-1=5%5==0 so it will become true and it will reset max and min page number limits.

**Line 69:** Here, we have disabled `prev` button when user is at 1st page.

**Line 78:** Here, we have disabled `next` button when user is at last page.

### Adding Page Indicators

Now our Pagination component is Almost completed one thing left is to add those three dots which indicates that there are more pages then displayed. Let's create them.

```javascript
import React, { useEffect, useState } from "react";
import "./style.css";

const renderData = (data) => {
  return (
    <ul>
      {data.map((todo, index) => {
        return <li key={index}>{todo.title}</li>;
      })}
    </ul>
  );
};

function PaginationComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/todos")
      .then((response) => response.json())
      .then((json) => setData(json));
  }, []);

  const handleClick = (event) => {
    setcurrentPage(Number(event.target.id));
  };

   const renderPageNumbers = pages.map((number) => {
      return (
        <li
          key={number}
          id={number}
          onClick={handleClick}
          className={currentPage == number ? "active" : null}
        >
          {number}
        </li>
      );

  });

    const handleNextbtn = () => {
    setcurrentPage(currentPage + 1);

    if (currentPage + 1 > maxPageNumberLimit) {
      setmaxPageNumberLimit(maxPageNumberLimit + pageNumberLimit);
      setminPageNumberLimit(minPageNumberLimit + pageNumberLimit);
    }
  };

  const handlePrevbtn = () => {
    setcurrentPage(currentPage - 1);

    if ((currentPage - 1) % pageNumberLimit == 0) {
      setmaxPageNumberLimit(maxPageNumberLimit - pageNumberLimit);
      setminPageNumberLimit(minPageNumberLimit - pageNumberLimit);
    }
  };

    let pageIncrementBtn = null;
  if (pages.length > maxPageNumberLimit) {
    pageIncrementBtn = <li onClick={handleNextbtn}> &hellip; </li>;
  }

  let pageDecrementBtn = null;
  if (minPageNumberLimit >= 1) {
    pageDecrementBtn = <li onClick={handlePrevbtn}> &hellip; </li>;
  }

  return (
    <>
      <h1>Todo List</h1> <br />
      {renderData(data)}

      <ul className="pageNumbers">
        <li>
          <button
            onClick={handlePrevbtn}
            disabled={currentPage == pages[0] ? true : false}
          >
            Prev
          </button>
        </li>
        {pageDecrementBtn}
        {renderPageNumbers}
        {pageIncrementBtn}
        <li>
          <button
            onClick={handleNextbtn}
            disabled={currentPage == pages[pages.length - 1] ? true : false}
          >
            Next
          </button>
        </li>
      </ul>

    </>
  );
}

export default PaginationComponent;
```

Above code block has the full code for this tutorial.

**Line no 59 and 64:** Here we have created two buttons with hellip; which is unicode for (... ). There are two buttons `pageIncrementBtn` will render when page length is > `maxPageNumberLimit` . while `pageDecrementBtn` will render when `minPageNumberLimit` >= 1.

**Line no 84 and 86:** Here we have rendered both of these (... ) buttons below and after the `renderPageNumbers` component.

Now your whole Pagination component is completed. Watch the above video to know about one more pagination component which loads items vertically.

---

## Related on DevDreaming

- [All Blog Posts](https://devdreaming.com/blogs)
- [Free Developer Tools](https://devdreaming.com/tools)
- [Video Tutorials](https://devdreaming.com/videos)
- [AI Tools for Developers](https://devdreaming.com/ai-tools)

---

_This is the Markdown twin of a page on **DevDreaming** -- free developer tutorials, tools, and AI resources. Source of truth: the canonical HTML URL above._