Pagination in React with useState
Used in this guide:Next.js 15.3.4
TypeScript
Tailwind CSS
Introduction
This tutorial walks through how to build a simple pagination system using React’s useState. You’ll display a list of items, navigate between pages, and allow users to jump to a specific page.
This example demonstrates how to implement basic pagination using React's useState. The list contains 24 fruits, and we paginate the display by showing 4 items per page. Users can navigate using "Prev" and "Next" buttons, or jump directly to a specific page using an input field. The pagination logic is fully handled on the client side, without needing external libraries or server-side data.
'use client'
import { useState } from "react";
const fruits = [
"Apple",
"Banana",
"Orange",
"Grape",
"Strawberry",
"Watermelon",
"Pineapple",
"Mango",
"Kiwi",
"Cherry",
"Peach",
"Pear",
"Plum",
"Lemon",
"Lime",
"Raspberry",
"Blueberry",
"Blackberry",
"Pomegranate",
"Fig",
"Apricot",
"Cantaloupe",
"Dragon fruit",
"Passion fruit"
]
export default function Home() {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 4;
const totalPages = Math.ceil(fruits.length / itemsPerPage);
const startingIndex = (currentPage - 1) * itemsPerPage; // first page starts at index 0, second age starts at index 4 etc...
const currentShowing = fruits.slice(startingIndex, startingIndex + itemsPerPage); // from starting index + 4 will be the fruits we want to display
const goToNext = () => setCurrentPage(prev => Math.min(prev + 1, totalPages));
const goToPrev = () => setCurrentPage(prev => Math.max(prev -1, 1));
return (
<div className="flex flex-col gap-4 p-8">
<h1 className="font-semibold text-lg">Pagination Tutorial</h1>
{currentShowing && (
<div className="flex gap-4">
{currentShowing.map((fruit) => (
<span
key={fruit}
className="bg-slate-600 py-2 px-4 rounded-md"
>{fruit}</span>
))}
</div>
)}
{fruits.length > 0 && (
<div className="flex items-center gap-4">
<button
onClick={goToPrev}
disabled={currentPage === 1}
className="bg-sky-600 text-sm py-2 px-4 cursor-pointer rounded-md disabled:opacity-50"
>Prev</button>
<span>Page {currentPage} of {totalPages}</span>
<button
onClick={goToNext}
disabled={currentPage === totalPages}
className="bg-sky-600 text-sm py-2 px-4 cursor-pointer rounded-md disabled:opacity-50"
>Next</button>
<div className="flex gap-2 items-center">
Go to page:
<input
type="number"
value={currentPage}
onChange={e => setCurrentPage(Number(e.target.value))}
min={1}
max={totalPages}
className="bg-slate-400 text-slate-800 p-2 "
/>
</div>
</div>
)}
</div>
);
}- We use useState to track the currentPage. The itemsPerPage is fixed at 4. From there, we calculate how many total pages we need.
- We compute the startingIndex to slice the fruits array and get only the items for the current page.
- goToNext and goToPrev handle clicking the Next and Prev buttons, while making sure the current page stays within valid limits.