ライブデモ Live Demo
ページ番号を表示するページネーション。アクティブなページはハイライト表示され、ホバー時にエフェクトが適用されます。
A pagination component displaying page numbers. The active page is highlighted with hover effects applied.
AI向け説明 AI Description
ページ番号を表示するページネーション。アクティブなページは`is-active`クラスで背景色とテキスト色を変更します。ホバー時は`transition`でスムーズに背景色とボーダーを変更します。前へ/次へボタンは`is-disabled`クラスで無効化し、`pointer-events: none`でクリック不可にします。
A pagination component displaying page numbers. The active page changes background and text color with the `is-active` class. On hover, background and border change smoothly with `transition`. Previous/next buttons are disabled with `is-disabled` class and `pointer-events: none` to prevent clicks.
調整可能パラメータ Adjustable Parameters
- active page style — アクティブページの背景色とテキスト色 background and text color for active page
- hover effect — ホバー時の背景色とボーダー background and border on hover
- total pages — 総ページ数 total number of pages
- ellipsis display logic — 省略表示のロジック(ページ1-3: 1 2 3 ... 10、ページ4-7: 1 ... 3 4 5 ... 10、ページ8-10: 1 ... 8 9 10) ellipsis display logic (pages 1-3: 1 2 3 ... 10, pages 4-7: 1 ... 3 4 5 ... 10, pages 8-10: 1 ... 8 9 10)
実装 Implementation
HTML + CSS + JS
<nav class="pagination" aria-label="Pagination"></nav>
<style>
.pagination {
display: flex;
gap: 8px;
align-items: center;
}
.pagination__item {
display: flex;
}
.pagination__link {
display: flex;
align-items: center;
justify-content: center;
min-width: 40px;
height: 40px;
padding: 0 12px;
border-radius: 8px;
color: #1d2242;
text-decoration: none;
transition: all 0.2s ease;
border: 1px solid transparent;
}
.pagination__link:hover {
background: #f5f7ff;
border-color: #dfe3f6;
}
.pagination__link.is-active {
background: #5c6ac4;
color: #fff;
border-color: #5c6ac4;
}
.pagination__link.is-disabled {
opacity: 0.4;
pointer-events: none;
cursor: not-allowed;
}
</style>
<script>
const pagination = document.querySelector(".pagination");
const totalPages = 10;
let currentPage = 1;
function renderPagination(page) {
const pages = [];
const showEllipsis = totalPages > 7;
if (!showEllipsis) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
if (page <= 3) {
pages.push(1, 2, 3, "ellipsis", totalPages);
} else if (page >= totalPages - 2) {
pages.push(1, "ellipsis", totalPages - 2, totalPages - 1, totalPages);
} else {
pages.push(1, "ellipsis", page - 1, page, page + 1, "ellipsis", totalPages);
}
}
pagination.innerHTML = "";
// 前ボタン
const prevItem = document.createElement("div");
prevItem.className = "pagination__item";
const prevLink = document.createElement("a");
prevLink.href = "#";
prevLink.className = `pagination__link ${page === 1 ? "is-disabled" : ""}`;
prevLink.setAttribute("aria-label", "Previous");
prevLink.textContent = "‹";
prevLink.addEventListener("click", (e) => {
e.preventDefault();
if (page > 1) renderPagination(page - 1);
});
prevItem.appendChild(prevLink);
pagination.appendChild(prevItem);
// ページ番号
pages.forEach((p) => {
const item = document.createElement("div");
item.className = "pagination__item";
if (p === "ellipsis") {
const ellipsis = document.createElement("span");
ellipsis.className = "pagination__link";
ellipsis.style.cssText = "pointer-events: none; opacity: 0.5;";
ellipsis.textContent = "...";
item.appendChild(ellipsis);
} else {
const link = document.createElement("a");
link.href = "#";
link.className = `pagination__link ${page === p ? "is-active" : ""}`;
link.textContent = p;
link.addEventListener("click", (e) => {
e.preventDefault();
renderPagination(p);
});
item.appendChild(link);
}
pagination.appendChild(item);
});
// 次ボタン
const nextItem = document.createElement("div");
nextItem.className = "pagination__item";
const nextLink = document.createElement("a");
nextLink.href = "#";
nextLink.className = `pagination__link ${page === totalPages ? "is-disabled" : ""}`;
nextLink.setAttribute("aria-label", "Next");
nextLink.textContent = "›";
nextLink.addEventListener("click", (e) => {
e.preventDefault();
if (page < totalPages) renderPagination(page + 1);
});
nextItem.appendChild(nextLink);
pagination.appendChild(nextItem);
currentPage = page;
}
renderPagination(1);
</script>
React (JSX + CSS)
// react/N-005.jsx
import { useState } from "react";
import "./N-005.css";
const totalPages = 10;
export default function Pagination() {
const [currentPage, setCurrentPage] = useState(1);
function getPages() {
const pages = [];
const showEllipsis = totalPages > 7;
if (!showEllipsis) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
if (currentPage <= 3) {
pages.push(1, 2, 3, "ellipsis", totalPages);
} else if (currentPage >= totalPages - 2) {
pages.push(1, "ellipsis", totalPages - 2, totalPages - 1, totalPages);
} else {
pages.push(1, "ellipsis", currentPage - 1, currentPage, currentPage + 1, "ellipsis", totalPages);
}
}
return pages;
}
return (
<nav className="pagination" aria-label="Pagination">
<div className="pagination__item">
<a
href="#"
className={`pagination__link ${currentPage === 1 ? "is-disabled" : ""}`}
onClick={(e) => {
e.preventDefault();
if (currentPage > 1) setCurrentPage(currentPage - 1);
}}
>
‹
</a>
</div>
{getPages().map((page, index) => (
<div key={index} className="pagination__item">
{page === "ellipsis" ? (
<span className="pagination__link" style={{ pointerEvents: "none", opacity: 0.5 }}>
...
</span>
) : (
<a
href="#"
className={`pagination__link ${currentPage === page ? "is-active" : ""}`}
onClick={(e) => {
e.preventDefault();
setCurrentPage(page);
}}
>
{page}
</a>
)}
</div>
))}
<div className="pagination__item">
<a
href="#"
className={`pagination__link ${currentPage === totalPages ? "is-disabled" : ""}`}
onClick={(e) => {
e.preventDefault();
if (currentPage < totalPages) setCurrentPage(currentPage + 1);
}}
>
›
</a>
</div>
</nav>
);
}
/* react/N-005.css */
.pagination {
display: flex;
gap: 8px;
align-items: center;
}
.pagination__item {
display: flex;
}
.pagination__link {
display: flex;
align-items: center;
justify-content: center;
min-width: 40px;
height: 40px;
padding: 0 12px;
border-radius: 8px;
color: #1d2242;
text-decoration: none;
transition: all 0.2s ease;
border: 1px solid transparent;
}
.pagination__link:hover {
background: #f5f7ff;
border-color: #dfe3f6;
}
.pagination__link.is-active {
background: #5c6ac4;
color: #fff;
border-color: #5c6ac4;
}
.pagination__link.is-disabled {
opacity: 0.4;
pointer-events: none;
cursor: not-allowed;
}
AIへの指示テンプレート AI Prompt Template
以下のテンプレートをコピーしてAIアシスタントに貼り付けると、このパターンの実装を依頼できます。 Copy the template below and paste it into your AI assistant to request an implementation of this pattern.