Customizable React Pagination Component (Typescript)

Customizable React Pagination Component (Typescript)

cnr-react-pagination

https://github.com/canerdemirci/cnr-react-pagination

https://www.npmjs.com/package/cnr-react-pagination

I have written a pagination component in React and published on npm. I aimed to make pagination easier and more useful. The component can navigate to the first page, previous page, next page, last page, and a specific page by number. There are page buttons based on the given range. When a page is selected, the page buttons will be rearranged if necessary. There is also a dropdown menu for selecting pages. The component's style and its icons and button range are customizable.

Here is a sample usage of the pagination component in React:

import Pagination from 'cnr-react-pagination'
import 'cnr-react-pagination/dist/index.css'

const dataLengthPerPage = 8;
const data = [
    {
      "name": "Adeel Solangi",
      "language": "Sindhi",
      "id": "V59OF92YF627HFY0",
      "bio": "Donec lobortis eleifend condimentum. Cras dictum dolor lacinia lectus vehicula rutrum. Maecenas quis nisi nunc. Nam tristique feugiat est vitae mollis. Maecenas quis nisi nunc.",
      "version": 6.1
    },
    // You can add more
];
const [currentPage, setCurrentPage] = useState(1);
const [shownData, setShownData] = useState(data.slice(0, dataLengthPerPage));

useEffect(() => {
  setShownData(data.slice((currentPage - 1) * dataLengthPerPage, currentPage * dataLengthPerPage));
}, [currentPage])

  return (
    <div className="App">
      <table className="dataTable">
        <thead>
          <tr>
            <th>Number</th>
            <th>Name</th>
            <th>Language</th>
            <th>ID</th>
            <th>BIO</th>
            <th>Version</th>
          </tr>
        </thead>
        <tbody>
          {shownData.map((d, i) =>
            <tr key={i}>
              <td>{i+((currentPage-1)*dataLengthPerPage)+1}</td>
              <td>{d.name}</td>
              <td>{d.language}</td>
              <td>{d.id}</td>
              <td>{d.bio}</td>
              <td>{d.version}</td>
            </tr>)}
        </tbody>
      </table>
<br />
      <Pagination
        dataLength={data.length}
        dataLengthPerPage={dataLengthPerPage}
        btn_range={10}
        onChange={(page) => {setCurrentPage(page)}}
        firstBtnIcon={<ImFirst />}
        lastBtnIcon={<ImLast />}
        prevBtnIcon={<ImPrevious2 />}
        nextBtnIcon={<ImNext2 />}
        pageButtonClassName='pagination_4_pageBtn'
        pageButtonSelectedClassName='pagination_4_pageBtn_selected'
        infoSectionClassName='pagination_4_infosection'
      />
<br />
      <Pagination
        dataLength={data.length}
        dataLengthPerPage={dataLengthPerPage}
        onChange={(page) => {setCurrentPage(page)}}
      />

The component's page button arrangement function:

This function rearranges the page buttons when the current page number changes. Its logic is explained in the comments.

function arrangeButtonArray(): number[] {
        /*
        ** We want this arrangment. Selected page is in parentheses.
        ** (Default range limit is 7)
        ** 1, 2, 3, 4, 5, 6, 7 or 16, 17, 18, 19, 20, 21, 22 => If clicked in range limit array remains same.
        ** 1, 2, 3, 4, 5, 6, 7 => (7) => 6, (7), 8, 9, 10, 11, 12
        ** 6, 7, 8, 9, 10, 11, 12 => (6) => 1, 2, 3, 4, 5, (6), 7
        */
        let newArr: number[] = [];

        // If there are as many pages as range limit.
        if (lastPage <= btn_range) {
            return newArr = Array.from({ length: lastPage }, (_, i) => i + 1);
        }

        // * FIRST
        // If selected page is 1.
        if (currentPage === 1) {
            newArr = Array.from({ length: btn_range }, (_, i) => i + 1);
        }
        // * LAST
        // If selected page is last page.
        else if (currentPage === lastPage) {
            newArr = Array.from({ length: btn_range }, (_, i) => i === 0 ? lastPage : lastPage - i).reverse();
        }
        // * PREVIOUS - 6, 7, 8, 9, 10, 11, 12 => (6) => 1, 2, 3, 4, 5, (6), 7
        // If selected page is in button array and is first and not 1.
        else if (currentPage <= buttonArray[0] && currentPage !== 1) {
            let start = Math.max(currentPage - btn_range + 2, 1);
            let end = start + btn_range;

            for (let i = start; i < end; i++) {
                newArr.push(i);
            }
        // * NEXT - 1, 2, 3, 4, 5, 6, 7 => (7) => 6, (7), 8, 9, 10, 11, 12
        // If selected page is in button array and is last and not last page.
        } else if (currentPage >= buttonArray[buttonArray.length - 1] && currentPage !== lastPage) {
            let start = currentPage - 1;
            let end = start + btn_range;

            if (end > lastPage) {
                end = lastPage + 1;
                start = lastPage - btn_range + 1;
            }

            for (let i = start; i < end; i++) {
                newArr.push(i);
            }
        }
        // If selected page is in button array.
        else {
            return [...buttonArray];
        }

        return newArr;
    }

and its using in rendering:

const [buttonArray, setButtonArray] = useState<number[]>(Array.from({ length: btn_range }, (_, i) => i + 1));

useEffect(() => {
        setButtonArray(arrangeButtonArray());
    }, [currentPage]);

{/* Page Buttons */}
                {buttonArray.map(i => <PageButton
                    key={i}
                    pageNumber={i}
                    isSelected={currentPage === i}
                    onClick={() => onChangePage(i)}
                    className={pageButtonClassName}
                    selectedClassName={pageButtonSelectedClassName}
                />)}

You can use the component on your react, next projects: https://www.npmjs.com/package/cnr-react-pagination

You can see the source code of the component and an example project in my GitHub repository: https://github.com/canerdemirci/cnr-react-pagination