raj
Setting Up Blog Pagination in Astro with Sanity CMS

Setting Up Blog Pagination in Astro with Sanity CMS

Scroll πŸ‘‡

🌟 Prerequisites

Before diving into pagination, set up your blog with Astro and Sanity CMS. For a detailed setup guide, check out this article to get your Astro-Sanity blog foundation ready.

πŸš€ Building Your Blog with Astro and Sanity CMS

Once you’ve completed the basic setup, we’ll focus on improving the user experience by implementing pagination. Here’s a breakdown of the steps:

πŸ“ 1: Update Blog Index Page for Pagination

Some changes in listing blogs on Astro frontend section

Let's assume we have a blog/index.astro page as follows with some changes to whatever you used when setting up using above link.

---
import BlogCard from "@/components/blog/blog-card.astro";
import SiteData from "@/constants/siteData.json";
import { getBlogs } from "@/helpers/server-actions";
import Main from "../../components/Main.astro";
import Layout from "../../layouts/Layout.astro";

const blogs = await getBlogs();
---

<Layout
  seo={{
    title: SiteData.pages.blog.title,
    description: SiteData.pages.blog.description
  }}
  keywords={SiteData.pages.blog.keywords}
>
  <Main className="mx-auto max-w-4xl pt-20 sm:pt-48">
    {
      blogs.length > 0 ? (
        <>
          <h1 class="bg-gradient-to-r from-[#ffff80] to-[#ff80bf] to-[60%] bg-clip-text pb-2 text-center text-2xl font-bold text-transparent sm:text-left sm:text-4xl md:text-5xl">
            Discover: Blog Articles and More
          </h1>
          <div class="flex flex-col gap-10">
            {blogs.map((blog) => (
              <BlogCard key={blog._id} blog={blog} />
            ))}
          </div>
        </>
      ) : (
        <p class="text-center text-2xl">No blogs found</p>
      )
    }
  </Main>
</Layout>

locate your blog listing page, typically named blog/index.astro. To enable pagination, rename it to blog/[...page].astro.

Replace the content in your updated blog/[...page].astro file with the following code:

---
import Main from "@/components/Main.astro";
import Pagination from "@/components/Pagination.astro";
import BlogCard from "@/components/blog/blog-card.astro";
import SiteData from "@/constants/siteData.json";
import { getAllBlogs } from "@/helpers/server-actions";
import Layout from "@/layouts/Layout.astro";
import type { GetStaticPaths, InferGetStaticPropsType } from "astro";

type Props = InferGetStaticPropsType<typeof getStaticPaths>;

export const getStaticPaths = (async ({ paginate }) => {
  const blogs = await getAllBlogs();

  return paginate(blogs, {
    pageSize: 3
  });
}) satisfies GetStaticPaths;

const { page } = Astro.props;

const firstUrl = page.currentPage > 1 ? `/blog` : undefined;
const lastUrl =
  page.currentPage < page.lastPage ? `/blog/${page.lastPage}` : undefined;
const prevUrl =
  page.currentPage > 2 ? `/blog/${page.currentPage - 1}` : "/blog";
const nextUrl =
  page.currentPage < page.lastPage
    ? `/blog/${page.currentPage + 1}`
    : undefined;
---

<Layout
  seo={{
    title: SiteData.pages.blog.title,
    description: SiteData.pages.blog.description
  }}
  keywords={SiteData.pages.blog.keywords}
>
  <Main className="mx-auto max-w-4xl pt-20 sm:pt-48">
    {
      page.data.length > 0 ? (
        <>
          <h1 class="bg-gradient-to-r from-[#ffff80] to-[#ff80bf] to-[60%] bg-clip-text pb-2 text-center text-2xl font-bold text-transparent sm:text-left sm:text-4xl md:text-5xl">
            Discover: Blog Articles and More
          </h1>
          <div class="flex flex-col gap-10">
            {page.data.map((blog) => (
              <BlogCard key={blog._id} blog={blog} />
            ))}
          </div>

          <Pagination
            currentPage={page.currentPage}
            lastPage={page.lastPage}
            prevUrl={prevUrl}
            nextUrl={nextUrl}
            firstUrl={firstUrl}
            lastUrl={lastUrl}
          />
        </>
      ) : (
        <p class="text-center text-2xl">No blogs found</p>
      )
    }
  </Main>
</Layout>

πŸ”„ 2: Create a Pagination Component

Pagination lets users easily navigate through multiple blog pages, so let’s build a Pagination component.

  1. Go to your components folder and create a new file named Pagination.astro at src/components/Pagination.astro.
  2. Add this code to manage page links dynamically:

src/components/Pagination.astro

---
import Link from "./Link.astro";

const { currentPage, lastPage, prevUrl, nextUrl, firstUrl, lastUrl } =
  Astro.props;

const getPageNumbers = (current: number, last: number) => {
  const range = [];
  for (
    let i = Math.max(1, current - 2);
    i <= Math.min(last, current + 2);
    i++
  ) {
    range.push(i);
  }
  return range;
};

const pageNumbers = getPageNumbers(currentPage, lastPage);
const urlParam = Astro.url.pathname;
---

<div class="mt-8 flex items-center justify-center space-x-3">
  {
    firstUrl && currentPage > 1 && (
      <Link
        text="First"
        href={firstUrl}
        style="secondary"
        classes="text-sm hover:bg-blue-50"
      />
    )
  }

  {
    urlParam !== "/blog" && (
      <Link
        text="Previous"
        href={prevUrl}
        style="secondary"
        icon={{ name: "tabler:arrow-big-left-line", side: "left" }}
        classes="flex gap-2 items-center text-sm hover:bg-blue-50"
      />
    )
  }

  {
    pageNumbers.map((page) => (
      <Link
        text={`${page}`}
        href={page === 1 ? "/blog" : `/blog/${page}`}
        style={page === currentPage ? "primary" : "secondary"}
        classes={`rounded-full w-10 h-10 flex items-center justify-center ${
          page === currentPage
            ? "bg-blue-500 text-white"
            : "bg-gray-100 text-gray-700 hover:bg-blue-50"
        }`}
      />
    ))
  }

  {
    nextUrl && (
      <Link
        text="Next"
        href={nextUrl}
        style="secondary"
        icon={{ name: "tabler:arrow-big-right-line", side: "right" }}
        classes="flex gap-2 items-center text-sm hover:bg-blue-50"
      />
    )
  }

  {
    lastUrl && currentPage < lastPage && (
      <Link
        text="Last"
        href={lastUrl}
        style="secondary"
        classes="text-sm hover:bg-blue-50"
      />
    )
  }
</div>

This component will allow visitors to navigate through your blog posts with ease.

πŸ”— 3: Set Up a Link Component for Navigation

To streamline navigation, create a Link component, which will manage individual page links efficiently.

  • Within src/components, add Link.astro.

Populate it with this code:

src/components/Link.astro

---
import { Icon } from "astro-icon";

interface Props {
  text: string;
  href: string;
  style: "primary" | "secondary";
  icon?: {
    name: string;
    side: "left" | "right";
  };
  isFilled?: boolean;
  borderVisible?: boolean;
  classes?: string;
}

const {
  text,
  href,
  style,
  icon,
  isFilled = true,
  borderVisible = false,
  classes,
  ...rest
} = Astro.props as Props;
---

<a
  href={href}
  class={`${
    style === "primary" ? "bg-blue-500 text-white" : "bg-gray-200 text-gray-600"
  } ${isFilled ? "rounded-full px-3 py-2" : "px-3 py-1"} ${
    borderVisible ? "border border-gray-300" : ""
  } ${classes} hover:shadow-md transition-all duration-150 ease-in-out`}
  {...rest}
>
  {icon && icon.side === "left" && <Icon name={icon.name} class="w-5" />}
  {text}
  {icon && icon.side === "right" && <Icon name={icon.name} class="w-5" />}
</a>

This will give you a seamless way to navigate through your blog pages. Enjoy building and sharing your thoughts with the world!
Don't forget to share this blog to your coding partners. Cheers πŸ₯‚