Astroのpaginate()を使ってページネーションコンポーネントをつくる
この記事は、microCMSのデータとAstroのpaginate関数を使用して、ChatGPTでページネーションコンポーネントを作成した備忘録です。
※microCMSの詳しい記事取得方法は含みません。
完成したページネーション

やりたいこと
- 最初・最後のページを表示するオプション
- ページ数が多い場合に「...」を表示する機能
- 前後のページへ移動するボタン
- 現在のページを示すインジケーター
- ページが1つしかない場合にページネーションを非表示にするオプション
- 全ページ表示ができる
- 1つのコンポーネントで管理できる
- aria-current/aria-labelの設定
ページの作成
getStaticPaths()でページを作成します。
/pages/blog/[...page].astro
---
import type { InferGetStaticPropsType, GetStaticPaths } from "astro";
import Pagination from "@components/Pagination.astro";
import { getAllBlogList } from "@libs/microcms";
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
export const getStaticPaths = (async ({ paginate }) => {
const allPosts = await getAllBlogList(); // 全記事取得
return paginate(allPosts, { pageSize: 1 }); // pageSize=1ページあたりの件数・わかりやすくするため1件にしてます
}) satisfies GetStaticPaths;
const { page } = Astro.props;
---
~略:記事一覧
<Pagination page={page} baseUrl="/blog" />
ページネーションの表示形式を独自オプションで柔軟にカスタマイズ
オプションは主に表示に関するもののみを管理し、それ以外の部分はHTMLソースで柔軟にカスタマイズできるようにしています。
コンポーネントは、アイテムごとに分けることもできますが、他の部分で再利用されることが少ないため、1つのコンポーネントで管理する形にしました☺️
Pagination.astro
---
const { page, baseUrl } = Astro.props;
const { lastPage, currentPage, url } = page;
const paginationOptions = {
alwaysShowPagination: true, // ページネーションを常に表示するか
showFirst: true, // 「最初のページ」ボタンを表示するか
showLast: true, // 「最後のページ」ボタンを表示するか
showItems: 5, // 表示するページ番号の最大数(0で全ページ表示、偶数指定時は自動で-1して奇数に調整)
showIndicator: true, // 現在のページを示すインジケーターを表示するか
showDots: true, // ページ数が多い場合に「...」を表示するか
dot: "...", // ドットの表記文字列
};
// 略
---
alwaysShowPagination: true
ページネーションは、記事の総数が pageSize
よりも少ない場合でも、常に表示するかどうかを設定するオプションです。もし記事の総数がページサイズより少ない場合でも、1ページのみが生成されます。それでもページネーションを常に表示するかどうか、このオプションで制御できます。

showFirst: true
最初のページへのリンクを表示するかどうかを設定するオプションです。true に設定すると、最初のページへのリンクが表示されます。
showLast: true
最後のページへのリンクを表示するかどうかを設定するオプションです。true に設定すると、最後のページへのリンクが表示されます。


showItems: 5
ページネーションで表示するページ番号の個数を設定するオプションです。
0
に設定すると、ページ番号を省略せず、全てのページ番号を表示します。- 偶数の値を設定した場合、自動的に1引かれて奇数の値に調整されます。これにより、左右のページリンクが均等に表示されるようになります。




showIndicator: true
現在のページ番号と総ページ数を表示するかどうかを設定するオプションです。true に設定すると、現在のページ番号と総ページ数(例: "3 / 10")が表示されます。
showDots: true
ページ番号の間にドット(...)を表示するオプションです。ページ数が多くなると、全てのページ番号を表示するのは煩雑になるため、ドットで省略する部分を表示します。
例えば、ページ数が10ページの場合、1ページ目、3ページ目、最終ページなどを表示し、それ以外はドットで省略されます。
dot: "..."
ドットを表示する文字列を設定するオプションです。デフォルトでは "..." が使用されますが、カスタマイズが可能です。
dot機能の適用に関する処理
- ページ数が
showItems
より多く、showItems
が3ページ以上の場合、ドット(...
)を表示します。 startPage
が1より大きい場合、最初のページ番号の後にドットを表示します。endPage
が総ページ数の1つ前より小さい場合、最後のページ番号の前にドットを表示します。- 最初のページは
1
に設定され、最後のページはtotalPages
に設定されます。
例えば、ページ数が3ページの場合は、ドットが表示されることなく、すべてのページ番号が表示されます。


Pagination.astro(全コード)
---
const { page, baseUrl } = Astro.props;
const { lastPage, currentPage, url } = page;
const paginationOptions = {
alwaysShowPagination: true,
showFirst: true,
showLast: true,
showItems: 5,
showIndicator: true,
showDots: true,
dot: "...",
};
let {
alwaysShowPagination,
showFirst,
showLast,
showDots,
showItems,
showIndicator,
dot,
} = paginationOptions;
// showItemsが偶数なら-1して奇数にする
if (showItems % 2 === 0 && showItems !== 0) {
showItems -= 1;
}
const totalPages = lastPage;
// 表示するページ番号を計算
let startPage, endPage;
if (showItems === 0 || totalPages <= showItems) {
startPage = 1;
endPage = totalPages;
} else if (currentPage <= Math.floor(showItems / 2) + 1) {
startPage = 1;
endPage = showItems;
} else if (currentPage > totalPages - Math.floor(showItems / 2)) {
startPage = totalPages - showItems + 1;
endPage = totalPages;
} else {
startPage = currentPage - Math.floor(showItems / 2);
endPage = currentPage + Math.floor(showItems / 2);
}
let pageNumbers = [...Array(endPage - startPage + 1)].map(
(_, i) => startPage + i
);
// dot機能の適用
if (showDots && totalPages >= showItems + 1 && showItems > 3) {
if (startPage > 1) pageNumbers[1] = 0;
if (endPage <= totalPages - 1) pageNumbers[pageNumbers.length - 2] = 0;
// 1番目を1、items番目を最後のページにする
pageNumbers[0] = 1;
pageNumbers[pageNumbers.length - 1] = totalPages;
}
const getAriaLabel = (pageNum: number) =>
pageNum !== currentPage
? `ページ ${pageNum}`
: `現在のページ(ページ ${pageNum})`;
---
{
alwaysShowPagination || totalPages > 1 ? (
<nav aria-label="ページネーション" class="pagination">
{showIndicator && (
<p class="indicator" aria-live="polite">
{currentPage} / {totalPages}
</p>
)}
<ul class="list">
{showFirst && url.first && (
<li class="item first">
<a
href={url.first}
class="link"
aria-label={`最初のページ(ページ 1)`}
>
«
</a>
</li>
)}
{url.prev && (
<li class="item prev">
<a
href={url.prev}
class="link"
aria-label={`前のページ(ページ ${currentPage - 1})`}
>
‹
</a>
</li>
)}
{pageNumbers.map((pageNum) => (
<li class="item">
{pageNum === 0 ? (
<span class="dot" aria-hidden="true">
{dot}
</span>
) : (
<a
href={`${baseUrl}${pageNum > 1 ? `/${pageNum}` : ""}`}
class:list={["link", pageNum === currentPage ? "current" : ""]}
aria-current={pageNum === currentPage ? "page" : undefined}
aria-label={getAriaLabel(pageNum)}
>
{pageNum}
</a>
)}
</li>
))}
{url.next && (
<li class="item next">
<a
href={url.next}
class="link"
aria-label={`次のページ(ページ ${currentPage + 1})`}
>
›
</a>
</li>
)}
{showLast && url.last && (
<li class="item last">
<a
href={url.last}
class="link"
aria-label={`最後のページ(ページ ${totalPages})`}
>
»
</a>
</li>
)}
</ul>
</nav>
) : null
}
まとめ
最初と最後の「前へ」「次へ」ボタンはpaginate関数を使用して実装しました。
間のページリストやドット表示は、ChatGPTを活用して基本的な構成を作り、その後、細かな条件調整を自分で行いました。ChatGPTにまとめて条件を提示すると希望通りにならないことがあるため、各オプションについて具体的な条件を提示し、段階を経て最終的な仕様に仕上げました。
📝参考サイト