Pagination component in react

Learn how to create pagination component in react.

Whenever we show limited no of items on any particular component, we either use pagination or lazy loading to show more items on certain user actions.

In pagination we divide the total no of items in different pages based on the limit that is provided. If user has to view more items then he needs to navigate to different page.

The navigation can be either done by moving next or prev in which only one change will happen or moving directly to the certain page.

Based on this we will create a simple pagination component in react.

It will be a functional component as we don’t want this component to maintain any state, it should always be controlled by a parent component to match the list of items being shown.

We will be using few extra packages to help us in development.

  • prop-types: It helps us to validate the props we will receive.
  • classnames: This packages helps us to use CSS classes as javascript objects and add styles conditionally, to make it work we just need to name our CSS file as filename.module.css.

Following is the folder structure of our component.
React Pagination Folder Structure

Now let us start creating our component. First, import all the required packages at the top.

import React from "react";
import PropTypes from "prop-types";
import styles from "./index.module.css";
import cx from "classnames";

const Pagination = props => {
  // Other code will go here
}

export default Pagination;

Before moving any further, first validate the props and set the default ones.

Pagination.propTypes = {
  totalItems: PropTypes.number.isRequired,
  perPage: PropTypes.number.isRequired,
  current: PropTypes.number.isRequired,
  onChange: PropTypes.func
};

Pagination.defaultProps = {
  current: 1
};

const Pagination = ({perPage, current, onChange, totalItems}) => {
  // Other code will go here
}

Our component will be composed of three part

  • Previous button:- It will navigate to the prev page.
  • List of pages:- We will show no of pages based on the total items and per page requested.
  • Next button:- To navigate to the next page.

To generate the number of pages we will have to do a simple mathematics. We will divide the total no of items with items per page and get the ceiling value of it.

Ceiling because even for one item we will need to show a page.

As we need this calculation often, it is better to create a function for this which will be doing this for us.

//Get total no of pages needed
  const getTotalPages = () => {
    return Math.ceil(totalItems / perPage);
  };

With this total count, we can generate the links for the pages.

  const total = getTotalPages();

  let links = [];
  for (let i = 1; i <= total; i++) {
    links.push(
      <li
        onClick={() => direct(i)}
        key={i}
        className={cx({ [styles.active]: current === i })}
      >
        {i}
      </li>
    );
  }

  return (
    <ul className={styles.wrapper}>
      <li onClick={prev}>&lt;</li>
      {links}
      <li onClick={next}>&gt;</li>
    </ul>
  );

cx({ [styles.active]: current === i }) will assign the active class on the current page.

lets create three different functions to listen the click events for next, prev, and direct click.

As it is a functional component and should always be controlled by parent, we are following the presentational/container rendering pattern.

In each of the function we will return the current active page number to the parent, along with it I am also returning two extra values for my reference, this is completely optional and you can skip them.

start will return the first number from where items list should start and end will return the last number.

Remember, our pagination is not zero based like an array, it starts from 1.

  const next = () => {
    const total = getTotalPages();

    if (current < total) {
      const start = current * perPage;
      const end = (current + 1) * perPage;
      onChange && onChange({ start, end, current: current + 1 });
    }
  };

  const prev = () => {
    const total = getTotalPages();

    if (current > 1 && current <= total) {
      const start = (current - 2) * perPage;
      const end = (current - 1) * perPage;
      onChange && onChange({ start, end, current: current - 1 });
    }
  };

  const direct = i => {
    if (current !== i) {
      const start = (i - 1) * perPage;
      const end = i * perPage;
      onChange && onChange({ start, end, current: i });
    }
  };

Complete code of pagination component in react.

import React from "react";
import PropTypes from "prop-types";
import styles from "./index.module.css";
import cx from "classnames";

const Pagination = ({perPage, current, onChange, totalItems}) => {
  //Get total no of pages needed
  const getTotalPages = () => {
    return Math.ceil(totalItems / perPage);
  };

  const next = () => {
    const total = getTotalPages();

    if (current < total) {
      const start = current * perPage;
      const end = (current + 1) * perPage;
      onChange && onChange({ start, end, current: current + 1 });
    }
  };

  const prev = () => {
    const total = getTotalPages();

    if (current > 1 && current <= total) {
      const start = (current - 2) * perPage;
      const end = (current - 1) * perPage;
      onChange && onChange({ start, end, current: current - 1 });
    }
  };

  const direct = i => {
    if (current !== i) {
      const start = (i - 1) * perPage;
      const end = i * perPage;
      onChange && onChange({ start, end, current: i });
    }
  };

  const total = getTotalPages();

  let links = [];
  for (let i = 1; i <= total; i++) {
    links.push(
      <li
        onClick={() => direct(i)}
        key={i}
        className={cx({ [styles.active]: current === i })}
      >
        {i}
      </li>
    );
  }

  return (
    <ul className={styles.wrapper}>
      <li onClick={prev}>&lt;</li>
      {links}
      <li onClick={next}>&gt;</li>
    </ul>
  );
};

Pagination.propTypes = {
  totalItems: PropTypes.number.isRequired,
  perPage: PropTypes.number.isRequired,
  current: PropTypes.number.isRequired,
  onChange: PropTypes.func
};

Pagination.defaultProps = {
  totalItems: 36,
  perPage: 5,
  current: 1
};

export default Pagination;

Hooray!, we have finished structuring the component, now lets design it.

Complete CSS of pagination component in react.

We will keep the designs very simple and just create the box of pages.

The active page will have an class to show the active state.

//index.module.css
.wrapper {
  display: inline-flex;
  justify-content: space-between;
  align-items: center;
  color: #5e6776;
  border: 1px solid #607D8B;
  padding: 0;
}

.wrapper > li {
  background-color: #fff;
  width: 20%;
  text-align: center;
  border-right: 1px solid #607D8B;
  padding: 8px 14px;
  list-style-type: none;
  cursor: pointer;
}

.wrapper > li:last-child {
  border: none;
}

.wrapper > li.active {
  background-color: #e9e9eb;
}

Input

//test.js
import React, { useState } from "react";
import Pagination from "./App";

const PaginationTest = () => {
  const [current, setCurrent] = useState(1);

  const onChange = ({ start, end, current }) => {
    setCurrent(current);
  };

  return (
    <Pagination
      current={current}
      onChange={onChange}
      totalItems={43}
      perPage={7}
    />
  );
}

export default PaginationTest;

Output

Pagination in react