N-005 Navigation medium

How to create a pagination ページネーションの作り方

Pagination component displaying page numbers. Customize active page highlight and hover effects. ページ番号を表示するページネーションコンポーネント。アクティブページのハイライトとホバーエフェクトをカスタマイズできます。

ライブデモ Live Demo

1

概要・用途・特徴Overview, Usage & Features

何ができるかWhat it does

Pagination component displaying page numbers. Customize active page highlight and hover effects.

ページ番号を表示するページネーションコンポーネント。アクティブページのハイライトとホバーエフェクトをカスタマイズできます。

どこで使うかWhere to use

website header, dashboard sidebar, mobile menu, admin panel

検索結果、ブログ記事一覧、商品カタログ、データテーブル

特徴Key features

Pagination component with prev/next arrows and numbered page buttons. Active page highlighted. Ellipsis for large page counts. Keyboard navigable. URL-friendly — updates query parameter on page change.

前/次矢印と番号付きページボタンを持つページネーションコンポーネント。アクティブページをハイライト。大きなページ数には省略記号。キーボードナビゲーション対応。URLフレンドリー — ページ変更時にクエリパラメータを更新。

調整可能パラメータ Adjustable Parameters

Parameter Default Description
active page stylebackground and text color for active page
hover effectbackground and border on hover
total pagestotal number of pages
ellipsis display logicellipsis 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 Code

// 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;
}
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>
  );
}
.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;
}

仕組みとカスタマイズHow It Works & Customization

仕組みHow it works

A JavaScript function generates page number buttons based on total pages and current page. An algorithm shows the first page, last page, current page ±1, and ellipses in between. Clicking a page updates the active state and triggers a data fetch or URL update. Prev/next buttons disable at the boundaries.

JavaScript関数が総ページ数と現在ページに基づいてページ番号ボタンを生成。アルゴリズムが最初のページ、最後のページ、現在ページ±1、省略記号を表示。ページのクリックがアクティブ状態を更新してデータフェッチまたはURL更新をトリガー。前/次ボタンが境界で無効化。

カスタマイズ方法Customization

Replace numbered buttons with a simple "Page X of Y" text for minimal UIs. Add a per-page selector (10 / 25 / 50 items) alongside the pagination. For infinite scroll, swap pagination entirely for an IntersectionObserver sentinel.

シンプルなUIのために番号付きボタンを"X / Y ページ"テキストに置き換え。ページネーションの横にページあたり件数セレクター(10/25/50件)を追加。無限スクロールの場合はページネーションをIntersectionObserverセンチネルに完全置き換え。

注意点Caveats

Wrap pagination in a <nav aria-label="Pagination"> landmark. Mark the active page button with aria-current="page". Disabled prev/next buttons should have aria-disabled="true" and remain in the tab order so users know they are at a boundary.

ページネーションを<nav aria-label="ページネーション">ランドマークでラップ。アクティブページボタンにaria-current="page"をマーク。無効な前/次ボタンはaria-disabled="true"を設定し、境界にいることをユーザーが分かるようタブ順序に残してください。

よくある質問 Frequently Asked Questions

How to customize the pagination? Paginationをカスタマイズするには?

Modify the CSS custom properties and class styles defined in the code section. Key adjustable values include colors, sizes, durations, and spacing. See the Adjustable Parameters section for specific variables.

コードセクションで定義されているCSSカスタムプロパティとクラススタイルを変更してください。色、サイズ、時間、間隔が主な調整可能値です。具体的な変数は調整可能パラメータセクションを参照してください。

How to use the pagination in React? ReactでPaginationを使うには?

Import the provided React component and its CSS file. The component accepts props for customization. Check the React code section for the full implementation and available props.

提供されているReactコンポーネントとCSSファイルをインポートしてください。コンポーネントのpropsでカスタマイズできます。完全な実装と利用可能なpropsはReactコードセクションを参照してください。

What are the performance implications of pagination? Paginationのパフォーマンスへの影響は?

This implementation uses CSS transforms and opacity for animations, which are GPU-accelerated. It's lightweight and doesn't cause layout thrashing. Consider using prefers-reduced-motion for accessibility.

この実装はCSSのtransformとopacityを使用しており、GPUアクセラレーションされます。軽量でレイアウトスラッシングを引き起こしません。アクセシビリティのためにprefers-reduced-motionの使用を検討してください。

AIへの指示テンプレート AI Prompt Template

以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.