raj
Setting Up Blog Pagination in Astro with Sanity CMS

Setting Up Blog Pagination in Astro with Sanity CMS

Build a beautiful blog with Astro and Sanity! This guide covers essential setups, pagination, and navigation for your blogging journey.

Last updated on: Nov 2024 Monday


๐ŸŒŸ 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.

1---
2import BlogCard from "@/components/blog/blog-card.astro";
3import SiteData from "@/constants/siteData.json";
4import { getBlogs } from "@/helpers/server-actions";
5import Main from "../../components/Main.astro";
6import Layout from "../../layouts/Layout.astro";
7
8const blogs = await getBlogs();
9---
10
11<Layout
12  seo={{
13    title: SiteData.pages.blog.title,
14    description: SiteData.pages.blog.description
15  }}
16  keywords={SiteData.pages.blog.keywords}
17>
18  <Main className="mx-auto max-w-4xl pt-20 sm:pt-48">
19    {
20      blogs.length > 0 ? (
21        <>
22          <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">
23            Discover: Blog Articles and More
24          </h1>
25          <div class="flex flex-col gap-10">
26            {blogs.map((blog) => (
27              <BlogCard key={blog._id} blog={blog} />
28            ))}
29          </div>
30        </>
31      ) : (
32        <p class="text-center text-2xl">No blogs found</p>
33      )
34    }
35  </Main>
36</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:

1---
2import Main from "@/components/Main.astro";
3import Pagination from "@/components/Pagination.astro";
4import BlogCard from "@/components/blog/blog-card.astro";
5import SiteData from "@/constants/siteData.json";
6import { getAllBlogs } from "@/helpers/server-actions";
7import Layout from "@/layouts/Layout.astro";
8import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
9
10type Props = InferGetStaticPropsType<typeof getStaticPaths>;
11
12export const getStaticPaths = (async ({ paginate }) => {
13  const blogs = await getAllBlogs();
14
15  return paginate(blogs, {
16    pageSize: 3
17  });
18}) satisfies GetStaticPaths;
19
20const { page } = Astro.props;
21
22const firstUrl = page.currentPage > 1 ? `/blog` : undefined;
23const lastUrl =
24  page.currentPage < page.lastPage ? `/blog/${page.lastPage}` : undefined;
25const prevUrl =
26  page.currentPage > 2 ? `/blog/${page.currentPage - 1}` : "/blog";
27const nextUrl =
28  page.currentPage < page.lastPage
29    ? `/blog/${page.currentPage + 1}`
30    : undefined;
31---
32
33<Layout
34  seo={{
35    title: SiteData.pages.blog.title,
36    description: SiteData.pages.blog.description
37  }}
38  keywords={SiteData.pages.blog.keywords}
39>
40  <Main className="mx-auto max-w-4xl pt-20 sm:pt-48">
41    {
42      page.data.length > 0 ? (
43        <>
44          <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">
45            Discover: Blog Articles and More
46          </h1>
47          <div class="flex flex-col gap-10">
48            {page.data.map((blog) => (
49              <BlogCard key={blog._id} blog={blog} />
50            ))}
51          </div>
52
53          <Pagination
54            currentPage={page.currentPage}
55            lastPage={page.lastPage}
56            prevUrl={prevUrl}
57            nextUrl={nextUrl}
58            firstUrl={firstUrl}
59            lastUrl={lastUrl}
60          />
61        </>
62      ) : (
63        <p class="text-center text-2xl">No blogs found</p>
64      )
65    }
66  </Main>
67</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

1---
2import Link from "./Link.astro";
3
4const { currentPage, lastPage, prevUrl, nextUrl, firstUrl, lastUrl } =
5  Astro.props;
6
7const getPageNumbers = (current: number, last: number) => {
8  const range = [];
9  for (
10    let i = Math.max(1, current - 2);
11    i <= Math.min(last, current + 2);
12    i++
13  ) {
14    range.push(i);
15  }
16  return range;
17};
18
19const pageNumbers = getPageNumbers(currentPage, lastPage);
20const urlParam = Astro.url.pathname;
21---
22
23<div class="mt-8 flex items-center justify-center space-x-3">
24  {
25    firstUrl && currentPage > 1 && (
26      <Link
27        text="First"
28        href={firstUrl}
29        style="secondary"
30        classes="text-sm hover:bg-blue-50"
31      />
32    )
33  }
34
35  {
36    urlParam !== "/blog" && (
37      <Link
38        text="Previous"
39        href={prevUrl}
40        style="secondary"
41        icon={{ name: "tabler:arrow-big-left-line", side: "left" }}
42        classes="flex gap-2 items-center text-sm hover:bg-blue-50"
43      />
44    )
45  }
46
47  {
48    pageNumbers.map((page) => (
49      <Link
50        text={`${page}`}
51        href={page === 1 ? "/blog" : `/blog/${page}`}
52        style={page === currentPage ? "primary" : "secondary"}
53        classes={`rounded-full w-10 h-10 flex items-center justify-center ${
54          page === currentPage
55            ? "bg-blue-500 text-white"
56            : "bg-gray-100 text-gray-700 hover:bg-blue-50"
57        }`}
58      />
59    ))
60  }
61
62  {
63    nextUrl && (
64      <Link
65        text="Next"
66        href={nextUrl}
67        style="secondary"
68        icon={{ name: "tabler:arrow-big-right-line", side: "right" }}
69        classes="flex gap-2 items-center text-sm hover:bg-blue-50"
70      />
71    )
72  }
73
74  {
75    lastUrl && currentPage < lastPage && (
76      <Link
77        text="Last"
78        href={lastUrl}
79        style="secondary"
80        classes="text-sm hover:bg-blue-50"
81      />
82    )
83  }
84</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

1---
2import { Icon } from "astro-icon";
3
4interface Props {
5  text: string;
6  href: string;
7  style: "primary" | "secondary";
8  icon?: {
9    name: string;
10    side: "left" | "right";
11  };
12  isFilled?: boolean;
13  borderVisible?: boolean;
14  classes?: string;
15}
16
17const {
18  text,
19  href,
20  style,
21  icon,
22  isFilled = true,
23  borderVisible = false,
24  classes,
25  ...rest
26} = Astro.props as Props;
27---
28
29<a
30  href={href}
31  class={`${
32    style === "primary" ? "bg-blue-500 text-white" : "bg-gray-200 text-gray-600"
33  } ${isFilled ? "rounded-full px-3 py-2" : "px-3 py-1"} ${
34    borderVisible ? "border border-gray-300" : ""
35  } ${classes} hover:shadow-md transition-all duration-150 ease-in-out`}
36  {...rest}
37>
38  {icon && icon.side === "left" && <Icon name={icon.name} class="w-5" />}
39  {text}
40  {icon && icon.side === "right" && <Icon name={icon.name} class="w-5" />}
41</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 ๐Ÿฅ‚