HextaUI

usePagination

Bir sayfayı ve sayfa sayısını, sayfa ilerledikçe uzunluğunu sabit tutarak, işlenecek sayfa ve üç nokta listesine dönüştürür.

siblings
7 items
"use client"

import * as React from "react"
import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { usePagination } from "@/hooks/use-pagination"

export function UsePaginationDemo() {
  const [page, setPage] = React.useState(6)
  const [siblings, setSiblings] = React.useState(1)
  const pagination = usePagination({ page, count: 20, siblings })

  return (
    <div className="flex w-full flex-col items-center gap-6">
      <nav aria-label="Pagination" className="flex items-center gap-1">
        <Button
          variant="ghost"
          size="icon-sm"
          aria-label="Previous page"
          disabled={!pagination.hasPrevious}
          onClick={() => setPage(pagination.page - 1)}
        >
          <IconChevronLeft className="rtl:rotate-180" />
        </Button>
        {pagination.items.map((item) =>
          item.type === "ellipsis" ? (
            <span
              key={item.position}
              aria-hidden="true"
              className="w-8 text-center text-sm text-muted-foreground"
            >
              …
            </span>
          ) : (
            <Button
              key={item.page}
              variant={item.page === pagination.page ? "secondary" : "ghost"}
              size="icon-sm"
              aria-current={item.page === pagination.page ? "page" : undefined}
              onClick={() => setPage(item.page)}
            >
              {item.page}
            </Button>
          )
        )}
        <Button
          variant="ghost"
          size="icon-sm"
          aria-label="Next page"
          disabled={!pagination.hasNext}
          onClick={() => setPage(pagination.page + 1)}
        >
          <IconChevronRight className="rtl:rotate-180" />
        </Button>
      </nav>
      <div className="flex items-center gap-3 text-sm text-muted-foreground">
        siblings
        <ToggleGroup
          size="sm"
          variant="outline"
          value={[String(siblings)]}
          onValueChange={(value) => {
            if (value[0]) {
              setSiblings(Number(value[0]))
            }
          }}
        >
          <ToggleGroupItem value="0">0</ToggleGroupItem>
          <ToggleGroupItem value="1">1</ToggleGroupItem>
          <ToggleGroupItem value="2">2</ToggleGroupItem>
        </ToggleGroup>
      </div>
      <code className="font-mono text-xs text-muted-foreground">
        {pagination.items.length} items
      </code>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/use-pagination.json

Hook'u ve bağımlı olduğu her şeyi projenize ekler.

import { usePagination } from "@/hooks/use-pagination"
const { items, page, hasPrevious, hasNext } = usePagination({
  page: currentPage,
  count: totalPages,
})

items.map((item) =>
  item.type === "ellipsis" ? (
    <span key={item.position}>…</span>
  ) : (
    <a key={item.page} href={`?page=${item.page}`}>{item.page}</a>
  )
)

Hook yalnızca hesabı yapar. İşlenecek sayfa ve üç nokta listesini döndürür, işaretlemeyi size bırakır; Pagination bağlantılarını böyle oluşturur. Bir carousel için noktalar veya tablo alt bilgisinde bir sayfa seçici gibi kendi sayfalayıcınızı oluşturmak için kullanın.

Liste her zaman ilk ve son boundaries sayfayı ve geçerli sayfanın her iki yanında siblings sayfayı gösterir. Üç nokta, iki veya daha fazla sayfalık her boşluğu doldurur. Tam bir sayfalık boşlukta bunun yerine o sayfa gösterilir; çünkü orada bir üç nokta kapladığından fazlasını gizlemezdi.

count: 20, siblings: 1, boundaries: 1

page 1    1  2  3  4  5  …  20
page 6    1  …  5  6  7  …  20
page 20   1  …  16 17 18 19 20

Yeterli sayfa olduğunda liste her zaman 2 × boundaries + 2 × siblings + 3 öğeye sahiptir. Uçlara yakınken pencere küçülmek yerine genişler. Uzunluk hiç değişmediği için sayfalayıcı genişliğini korur ve sayfalarda gezinirken sonraki ve önceki düğmeler imlecin altında kalır.

  • count ve page sınırlanır: sondan sonraki bir sayfa son sayfa olur ve sonlu bir sayı olmayan her şey varsayılana düşer.
  • 0 değerli bir count hiç öğe ve 0 değerli bir page döndürür; böylece boş bir tablo özel durum olmadan hiçbir şey işleyebilir.
  • siblings ve boundaries 0 ile 10 arasındadır.
  • Üç noktaların start veya end değerinde kararlı bir position değeri vardır. Bunu React key'i olarak kullanın.

Noktalar

boundaries: 0 ile liste yalnızca geçerli sayfanın çevresinde bir penceredir. Üç noktalar küçük noktalara dönüşür; böylece uzun bir slayt kümesi hiçbir zaman beşten fazla hedefe ihtiyaç duymaz.

"use client"

import * as React from "react"

import { usePagination } from "@/hooks/use-pagination"

export function UsePaginationDots() {
  const [page, setPage] = React.useState(1)
  const { items } = usePagination({
    page,
    count: 12,
    siblings: 1,
    boundaries: 0,
  })

  return (
    <nav aria-label="Slides" className="flex items-center gap-1">
      {items.map((item) =>
        item.type === "ellipsis" ? (
          <span
            key={item.position}
            aria-hidden="true"
            className="size-1 rounded-full bg-border"
          />
        ) : (
          <button
            key={item.page}
            type="button"
            aria-label={`Slide ${item.page}`}
            aria-current={item.page === page ? "true" : undefined}
            onClick={() => setPage(item.page)}
            className="flex size-6 items-center justify-center rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden"
          >
            <span className="h-2 w-2 rounded-full bg-muted-foreground/30 transition-all duration-300 ease-out-quint in-aria-[current=true]:w-5 in-aria-[current=true]:bg-foreground motion-reduce:transition-none" />
          </button>
        )
      )}
    </nav>
  )
}
  • Geçerli sayfayı aria-current="page" ile işaretleyin ve listeyi etiketli bir <nav> içine sarın.
  • Üç noktaları aria-hidden ile ekran okuyuculardan gizleyin. Sayfa numaralarının vermediği hiçbir bilgi taşımazlar.
  • Basamaklar değişirken düğmelerin genişliği değişmesin diye sayfa numaralarını tabular-nums ile gösterin.
PropTürVarsayılan
countToplam sayfa sayısı.
number–
page1'den başlayan geçerli sayfa.
number1
siblingsGeçerli sayfanın her iki yanında gösterilecek sayfalar.
number1
boundariesBaşta ve sonda her zaman gösterilecek sayfalar.
number1
ÖzellikAçıklama
itemsSırayla işlenecek PaginationItemData[].
pageSınırlanmış geçerli sayfa.
countSınırlanmış sayfa sayısı.
hasPreviousBundan önce bir sayfa olup olmadığı.
hasNextBundan sonra bir sayfa olup olmadığı.
type PaginationItemData =
  | { type: "page"; page: number }
  | { type: "ellipsis"; position: "start" | "end" }

Pagination.