Pagination
ページネーションコンポーネント。ページ間のナビゲーションを提供します。
インポート
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
usePaginationRange,
PAGINATION_DOTS,
} from '@caroainc/ui-components/client'個別サブパス(バンドルサイズを抑えたい場合):
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
usePaginationRange,
PAGINATION_DOTS,
} from '@caroainc/ui-components/pagination'基本的な使い方
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>省略記号付き
多数のページがある場合は PaginationEllipsis を使用します。この例は手書きで固定位置に省略記号を配置していますが、現在ページに応じて省略記号の位置を動的に計算したい場合は下記の usePaginationRange を使ってください。
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">10</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>usePaginationRangeフック(動的な省略記号)
usePaginationRange(current, total, siblingCount?) は、現在ページ・総ページ数から、先頭ページ・末尾ページ・現在ページ周辺(siblingCount件ずつ、デフォルト1)・省略記号(PAGINATION_DOTS)を含むページ番号レンジを計算して返します。手書きで省略記号の位置を管理する必要がなくなります。
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
usePaginationRange,
PAGINATION_DOTS,
} from '@caroainc/ui-components/client'
function PaginationRangeDemo() {
const [page, setPage] = useState(1)
const totalPages = 10
const range = usePaginationRange(page, totalPages)
return (
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
disabled={page <= 1}
onClick={(e) => { e.preventDefault(); setPage((p) => Math.max(1, p - 1)) }}
/>
</PaginationItem>
{range.map((item, i) =>
item === PAGINATION_DOTS ? (
<PaginationItem key={`dots-${i}`}>
<PaginationEllipsis />
</PaginationItem>
) : (
<PaginationItem key={item}>
<PaginationLink
href="#"
isActive={item === page}
onClick={(e) => { e.preventDefault(); setPage(item) }}
>
{item}
</PaginationLink>
</PaginationItem>
)
)}
<PaginationItem>
<PaginationNext
href="#"
disabled={page >= totalPages}
onClick={(e) => { e.preventDefault(); setPage((p) => Math.min(totalPages, p + 1)) }}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
)
}ページサイズ選択と組み合わせる
Selectと組み合わせて、1ページあたりの件数を切り替えるUIを構成できます。
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@caroainc/ui-components/client'
function PaginationWithPageSizeDemo() {
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState('10')
return (
<div className="flex items-center justify-between gap-4">
<div className="flex items-center gap-2 text-sm text-sub-foreground">
<span>表示件数</span>
<Select
value={pageSize}
onValueChange={(value) => { setPageSize(value); setPage(1) }}
>
<SelectTrigger className="w-20">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="10">10</SelectItem>
<SelectItem value="20">20</SelectItem>
<SelectItem value="50">50</SelectItem>
</SelectContent>
</Select>
</div>
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
href="#"
onClick={(e) => { e.preventDefault(); setPage((p) => Math.max(1, p - 1)) }}
/>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>{page}</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext
href="#"
onClick={(e) => { e.preventDefault(); setPage((p) => p + 1) }}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
)
}asChildでのリンクコンポーネント差し替え(Next.js等)
PaginationLinkはasChildに対応しています。SPAルーティング(Next.jsのLink等)に差し替える場合に使用してください(PaginationPrevious / PaginationNextは内部でアイコン+テキストの複数childrenを持つためasChildは使用できません。差し替えが必要な場合はPaginationLinkを直接使用してください)。
import Link from 'next/link'
import { PaginationLink, PaginationItem } from '@caroainc/ui-components/client'
<PaginationItem>
<PaginationLink asChild isActive={page === 2}>
<Link href="/items?page=2">2</Link>
</PaginationLink>
</PaginationItem>hrefを使わずクリックハンドラのみで制御するSPAパターンでは、hrefを省略してonClickだけを渡すこともできます(<a>のままhrefなしで描画されるため、キーボード操作を保つ場合はhref="#" + preventDefault()を推奨します)。
<PaginationLink onClick={() => setPage(2)} isActive={page === 2}>
2
</PaginationLink>サイズ
size プロパティでサイズを変更できます。
{/* Small */}
<PaginationLink href="#" size="sm">1</PaginationLink>
{/* Default */}
<PaginationLink href="#" size="default">1</PaginationLink>
{/* Large */}
<PaginationLink href="#" size="lg">1</PaginationLink>無効状態
最初や最後のページでは disabled を使用してナビゲーションを無効化します。
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" disabled />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>ページ番号のみ
前後ボタンなしでページ番号のみを表示することもできます。
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>2</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">4</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">5</PaginationLink>
</PaginationItem>
</PaginationContent>
</Pagination>Props
PaginationLink
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | - | リンク先URL |
isActive | boolean | false | 現在のページかどうか |
disabled | boolean | false | 無効状態 |
size | 'default' | 'sm' | 'lg' | 'default' | サイズ |
asChild | boolean | false | 子要素をリンクとしてレンダリング(Next.jsのLink等への差し替え用) |
PaginationPrevious / PaginationNext
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | - | リンク先URL |
disabled | boolean | false | 無効状態 |
size | 'default' | 'sm' | 'lg' | 'default' | サイズ |
asChildは使用できません(内部でアイコン+テキストの複数childrenをPaginationLinkへ渡しているため)。リンクコンポーネントを差し替えたい場合はPaginationLinkを直接使用してください。
usePaginationRange
| Prop | Type | Default | Description |
|---|---|---|---|
current* | number | - | 現在のページ番号(1始まり) |
total* | number | - | 総ページ数 |
siblingCount | number | 1 | 現在ページの前後に表示するページ数 |
戻り値は (number | typeof PAGINATION_DOTS)[](例: [1, 'DOTS', 4, 5, 6, 'DOTS', 10])です。PAGINATION_DOTSをimportして比較に使用してください。