Setting Up Blog Pagination in Astro with Sanity CMS
Table of contents
- π Prerequisites
- π Building Your Blog with Astro and Sanity CMS
- π 1: Update Blog Index Page for Pagination
- π 2: Create a Pagination Component
- π 3: Set Up a Link Component for Navigation
π 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.
- Go to your components folder and create a new file named Pagination.astro at src/components/Pagination.astro.
- 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 π₯