PaginationControls
Open in ChatGPTA compact, Astro-native pagination system that syncs directly with Astro’s routing and pagination APIs, offering modular controls, dynamic page indices, and zero client-side JavaScript. Ideal for clean, scalable multi-page navigation in Astro projects.
Install
pnpm dlx hybrid-astro-ui@latest add pagination-controls npx hybrid-astro-ui@latest add pagination-controls yarn dlx hybrid-astro-ui@latest add pagination-controls bunx hybrid-astro-ui@latest add pagination-controls Usage
---
import { Pagination,
PaginationButton,
PaginationIndex,
PaginationIndexContainer
} from "@/src/components/hybrid-astro-u/pagination-controls"
---
<Pagination>
<PaginationButton path={undefined}> Prev </PaginationButton>
<PaginationIndexContainer>
<PaginationIndex
path="/components/1"
active={false}
label={1}
/>
<PaginationIndex
path="/components/3"
active={true}
label={2}
/>
<PaginationIndex
path="/components/3"
active={false}
label={3}
/>
</PaginationIndexContainer>
<PaginationButton path="/components/2"> Next </PaginationButton>
</Pagination>
Real case
The following example demonstrates how to integrate the pagination system into a real page. The first step is to create a component that wraps all the logic required to render the pagination controls. This component handles generating page links, calculating the visible range, and rendering the “Prev” and “Next” buttons.
---
// components/Controls.astro
import { type Page } from "astro";
import { Pagination,
PaginationButton,
PaginationIndex,
PaginationIndexContainer
} from "@/src/components/hybrid-astro-u/pagination-controls"
---
interface Props {
paginationInfo: Page;
}
const page_index = Astro.params;
const { paginationInfo } = Astro.props as Props;
const pages = Array.from({ length: 5 }, (_, i) => {
if (paginationInfo.currentPage + i > paginationInfo.lastPage) {
return null;
}
return {
href: `/components/${paginationInfo.currentPage + i}`,
label: paginationInfo.currentPage + i,
};
}).filter((v) => v !== null);
---
<Pagination>
<PaginationButton path={paginationInfo.url.prev}> Prev </PaginationButton>
<PaginationIndexContainer>
{
pages.map((p) => (
<PaginationIndex
path={p.href}
active={parseInt(page_index.page || "1") === p.label}
label={p.label}
/>
))
}
</PaginationIndexContainer>
<PaginationButton path={paginationInfo.url.next}> Next </PaginationButton>
</Pagination>
In this example, the Controls component builds a dynamic list of pages based on the paginationInfo passed from the parent. The pages array automatically excludes invalid pages, ensuring that no out-of-range links are rendered. Each item is then passed to PaginationIndex, which highlights the active page based on the current URL parameters.
Once the Controls component is ready, you can import and use it directly inside any page that requires pagination. Here, we generate static paths using createCollectionPagination, which creates individual routes for each page of the collection.
---
// components/[page].astro
import { createCollectionPagination } from "@/src/lib/utils";
import Controls from "......."
export const getStaticPaths = createCollectionPagination({
collection: "components",
pageSize: 3,
sortByFn: (a, b) => {
const titleA = a.data.title.toUpperCase();
const titleB = b.data.title.toUpperCase();
if (titleA < titleB) {
return -1;
}
if (titleA > titleB) {
return 1;
}
return 0;
},
filterFn: (item) => item.data.category === "components",
});
const { page } = Astro.props;
---
<section class="w-full flex flex-col items-center justify-center py-20">
<div class="flex flex-col gap-2 prose dark:prose-invert items-center">
{
page.data.map((item) => (
<div>
<h2>{item.data.title}</h2>
<p>{item.data.description}</p>
</div>
))
}
<Controls paginationInfo={page} />
</div>
</section>
Inside the template, we iterate through page.data to display the items that belong to the current page.
Finally, we render <Controls paginationInfo={page} /> to display the pagination controls below the content.
This structure keeps your code clean and modular, allowing you to reuse the pagination system across multiple sections of your project with minimal effort.
createCollectionPagination — Quick Guide
createCollectionPagination generates a getStaticPaths function that automatically paginates an Astro collection. You provide:
-
collection: the collection name
-
pageSize: items per page
-
sortByFn (optional)
-
filterFn (optional)
Example
---
export const getStaticPaths = createCollectionPagination({
collection: "components",
pageSize: 3,
});
---