GatsbyJS: Numbered Pagination Component

Published on
-
2 min read

I created a simple GatsbyJS pagination component that would work in a similar way to my earlier ASP.NET Core version, where the user will be able to paginate through a list using the standard "Previous" and "Next" links as well as selecting individual page numbers.

Like the ASP.NET Core version, I have tried to make this pagination component very portable, so there shouldn't be any issues in adding this straight into your project. Plug and play!

import * as React from 'react'
import { Link } from 'gatsby'
import PropTypes from 'prop-types'

// Create URL path for numeric pagination
const getPageNumberPath = (currentIndex, basePath) => {
  if (currentIndex === 1) {
    return basePath
  }
  
  return `${basePath}/page-${(currentIndex)}`
}

// Create an object array of pagination numbers. 
// The number of page numbers to render is set to 5.
const getPaginationGroup = (basePath, currentPage, pageCount, noOfPagesNos = 5) => {
    let startPage = currentPage;

    if (startPage === 1 || startPage === 2 || pageCount < noOfPagesNos)
        startPage = 1;
    else
        startPage -= 2;

    let maxPage = startPage + noOfPagesNos;

    if (pageCount < maxPage) {
        maxPage = pageCount + 1
    }

    if (maxPage - startPage !== noOfPagesNos && maxPage > noOfPagesNos) {
        startPage = maxPage - noOfPagesNos;
    }

    let paginationInfo = [];

    for (let i = startPage; i < maxPage; i++) {        
        paginationInfo.push({
            number: i,
            url: getPageNumberPath(i, basePath),
            isCurrent: currentPage === i
        });
    }

    return paginationInfo;
};

export const Pagination = ({ pageInfo, basePath }) => {
    if (!pageInfo) 
        return null

    const { currentPage, pageCount } = pageInfo

    // Create URL path for previous and next buttons
    const prevPagePath = currentPage === 2 ? basePath : `${basePath}/page-${(currentPage - 1)}`
    const nextPagePath = `${basePath}/page-${(currentPage + 1)}`
    
    if (pageCount > 1) { 
        return (
                <ol>
                    {currentPage > 1 ? 
                        <li>
                            <Link to={prevPagePath}>
                                Go to previous page
                            </Link>
                        </li> : null}       
                    {getPaginationGroup(basePath, currentPage, pageCount).map((item, i) => {
                        return (
                            <li key={i}>
                                <Link to={item.url} className={`${item.isCurrent ?  "is-current" : ""}`}>
                                    Go to page {item.number}
                                </Link>
                            </li>
                        )
                    })}
                    {currentPage !== pageCount ?
                        <li>
                            <Link to={nextPagePath}>
                                Go to next page
                            </Link>
                        </li> : null}
                </ol>
        )
    }
    else {
        return null
    }
  }

Pagination.propTypes = {
    pageInfo: PropTypes.object,
    basePath: PropTypes.string
}

export default Pagination;

This component requires just two parameters:

  1. pageInfo: A page context object created when Gatsby generates the site pages. The object should contain two properties consisting of the current page the that is being viewed (currentPage) and total number of pages (pageCount).
  2. basePath: The parent URL of where the pagination component will reside. For example, if your listing page is "/customers", this will be the base path. The pagination component will then prefix this to construct URL's in the format of - "/customers/page-2".

Before you go...

If you've found this post helpful, you can buy me a coffee. It's certainly not necessary but much appreciated!

Buy Me A Coffee

Leave A Comment

If you have any questions or suggestions, feel free to leave a comment. I do get inundated with messages regarding my posts via LinkedIn and leaving a comment below is a better place to have an open discussion. Your comment will not only help others, but also myself.