← Back to list

Building a Pagination System in Next.js using sadcn

This guide shows how to create a simple pagination system in Next.js using a dummy JSON dataset. It’s designed for users with no backend…

bishwa jung shah · 2025-02-07 12:09 · 8 claps · 3.6 min read
#pagination-in-react #pagination #pagination-using-sadcn
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Building a Pagination System in Next.js using sadcn

This guide shows how to create a simple pagination system in Next.js using a dummy JSON dataset. It’s designed for users with no backend experience, offering an easy setup for implementing pagination without complex server-side configurations.

Note: This demo assumes you already have a Next.js project set up and are looking to gain experience in implementing a pagination system.

Step 1: Setting Up the Backend API for Pagination

We will create a simple API endpoint in our Next.js project that fetches paginated data from the DummyJSON API.

File Structure

/app
  /api
    /pagination
      route.ts

API Implementation (api/pagination/route.ts)

import axios from "axios";
export async function GET(request: Request) {
  try {
    const { searchParams } = new URL(request.url);
    const page = parseInt(searchParams.get("page") || "1");
    const limit = parseInt(searchParams.get("limit") || "10");
// Fetch all data from DummyJSON API
    const response = await axios.get("https://dummyjson.com/products?limit=0");
    const products = response.data.products;
    // Calculate total pages
    const totalProducts = products.length;
    const totalPages = Math.ceil(totalProducts / limit);
    // Paginate the products
    const startIndex = (page - 1) * limit;
    const paginatedData = products.slice(startIndex, startIndex + limit);
    return new Response(
      JSON.stringify({
        data: paginatedData,
        current_data_length: paginatedData.length,
        current_page: page,
        total_page: totalPages,
      }),
      { status: 200, headers: { "Content-Type": "application/json" } }
    );
  } catch (error) {
    console.error("Error:", error);
    return new Response(
      JSON.stringify({ error: "Something went wrong" }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }
}

This API fetches product data, calculates total pages, and returns paginated results based on query parameters.

Step 2: Creating the Pagination Wrapper Component

We will build a reusable **PaginationWrapper** component using Shadcn's pagination utilities.

note: you have to install the pagination, button ,skeleton and card from sadcn website

PaginationWrapper (components/PaginationWrapper.tsx)

import React from "react";
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationPrevious,
  PaginationNext,
  PaginationEllipsis,
} from "@/components/ui/pagination";
interface PaginationWrapperProps {
  totalPages: number;
  currentPage: number;
  onPageChange: (page: number) => void;
  disabled?: boolean;
}
const PaginationWrapper: React.FC<PaginationWrapperProps> = ({
  totalPages,
  currentPage,
  onPageChange,
  disabled = false,
}) => {
  const getPages = () => {
    const pages = [];
    for (let i = 1; i <= totalPages; i++) {
      pages.push(i);
    }
    return pages;
  };
  return (
    <Pagination>
      <PaginationContent>
        <PaginationPrevious
          onClick={() => {
            if (!disabled && currentPage > 1) onPageChange(currentPage - 1);
          }}
        />
        {getPages().map((page) =>
          Math.abs(page - currentPage) < 2 || page === 1 || page === totalPages ? (
            <PaginationItem key={page}>
              <PaginationLink
                isActive={page === currentPage}
                onClick={() => onPageChange(page)}
              >
                {page}
              </PaginationLink>
            </PaginationItem>
          ) : (
            page === currentPage + 2 && <PaginationEllipsis key={page} />
          )
        )}
        <PaginationNext
          onClick={() => {
            if (!disabled && currentPage < totalPages) onPageChange(currentPage + 1);
          }}
        />
      </PaginationContent>
    </Pagination>
  );
};
export default PaginationWrapper;

This component handles pagination logic and displays the appropriate page numbers, next, and previous buttons.

Step 3: Building the Product List Component with Pagination

Next, we will create a Product Pagination component that fetches paginated data from the backend API and displays it with a pagination control.

Product Pagination Component (components/ProductPagination.tsx)

"use client";
import { useState, useEffect } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import Image from "next/image";
import PaginationWrapper from "./PaginationWrapper";
interface Product {
  id: number;
  title: string;
  description: string;
  price: number;
  thumbnail: string;
}
interface ApiResponse {
  data: Product[];
  current_data_length: number;
  current_page: number;
  total_page: number;
}
export default function ProductPagination() {
  const [products, setProducts] = useState<Product[]>([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [totalPages, setTotalPages] = useState(0);
  const [isLoading, setIsLoading] = useState(true);
  const searchParams = useSearchParams();
  const router = useRouter();
  const fetchProducts = async (page: number) => {
    setIsLoading(true);
    try {
      const response = await fetch(`/api/pagination?page=${page}&limit=10`);
      const data: ApiResponse = await response.json();
      setProducts(data.data);
      setCurrentPage(data.current_page);
      setTotalPages(data.total_page);
    } catch (error) {
      console.error("Error fetching products:", error);
    } finally {
      setIsLoading(false);
    }
  };
  useEffect(() => {
    const page = Number(searchParams.get("page")) || 1;
    fetchProducts(page);
  }, [searchParams]);
  const handlePageChange = (page: number) => {
    router.push(`?page=${page}`);
  }; // for simple i have just push you can optimize as you want
  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">Product List</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-4">
        {isLoading
          ? Array(10)
              .fill(0)
              .map((_, index) => (
                <Card key={index} className="w-full">
                  <CardHeader>
                    <Skeleton className="h-4 w-[250px]" />
                  </CardHeader>
                  <CardContent>
                    <Skeleton className="h-4 w-[200px] mb-2" />
                    <Skeleton className="h-4 w-[150px]" />
                  </CardContent>
                </Card>
              ))
          : products.map((product) => (
              <Card key={product.id} className="w-full">
                <CardHeader>
                  <CardTitle>{product.title}</CardTitle>
                </CardHeader>
                <CardContent>
                  <p className="text-sm text-gray-500 mb-2">{product.description}</p>
                  <p className="font-bold">${product.price.toFixed(2)}</p>
                  <Image
                    src={product.thumbnail || "/placeholder.svg"}
                    alt={product.title}
                    width={250}
                    height={160}
                    className="mt-2 w-full h-40 object-cover rounded-md"
                  />
                </CardContent>
              </Card>
            ))}
      </div>
      <div className="flex justify-center mt-4">
        <PaginationWrapper
          totalPages={totalPages}
          currentPage={currentPage}
          onPageChange={handlePageChange}
          disabled={isLoading}
        />
      </div>
    </div>
  );
}

Step 4: Rendering the Product Pagination Component

Finally, integrate the ProductPagination component in your Next.js page.

import ProductPagination from "./components/ProductPagination";
export default function Home() {
  return (
    <main className="min-h-screen bg-background">
      <ProductPagination />
    </main>
  );
}

Conclusion

In this tutorial, we built a full-fledged pagination system in Next.js. We used Shadcn’s Pagination component for the UI and created a custom backend API for fetching paginated data. This approach ensures a seamless and scalable user experience.

Feel free to customize the styles and pagination logic according to your needs. Happy coding!

In short I have write a raw code here


메타데이터
post_id
b7a3e79cf1e2
slug
building-a-pagination-system-in-next-js-using-sadcn-b7a3e79cf1e2
url
https://medium.com/@shahbishwa21/building-a-pagination-system-in-next-js-using-sadcn-b7a3e79cf1e2
canonical_url
https://medium.com/@shahbishwa21/building-a-pagination-system-in-next-js-using-sadcn-b7a3e79cf1e2
author_url
https://medium.com/@shahbishwa21
status
ok
fetched_at
2026-06-09 15:37:30