Ir al contenido
NavegaciónServer Component

Pagination

Anterior, números con «…» y siguiente. Con links de verdad o con botones.

import { Pagination } from "sebs7n-ui/pagination"

Ejemplos

Con botones

Para una lista que se pagina sin cambiar de URL: `onPageChange` recibe la página destino.

import { Pagination } from "sebs7n-ui/pagination"
import { useState } from "react"

function ConBotones() {
  const [page, setPage] = useState(1)
  return (
    <div className="flex w-full flex-col items-center gap-4">
      <p className="text-callout text-label-secondary">Página {page} de 10</p>
      <Pagination onPageChange={setPage} page={page} pageCount={10} />
    </div>
  )
}

Si la página vive en la URL, `render`: son `<a>` de verdad, el crawler los ve y se abren en una pestaña nueva.

import Link from "next/link"
import { Pagination } from "sebs7n-ui/pagination"

function ConLinks() {
  return (
    <Pagination
      page={4}
      pageCount={12}
      render={(page) => <Link href={`/docs/components/pagination?page=${page}`} scroll={false} />}
    />
  )
}

Muchas páginas y tamaño chico

El ancho no salta: cuando un «…» desaparece, lo reemplaza un número.

import { Pagination } from "sebs7n-ui/pagination"
import { useState } from "react"

function MuchasPaginas() {
  const [page, setPage] = useState(50)
  return <Pagination onPageChange={setPage} page={page} pageCount={100} size="sm" />
}

Props

Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».

Pagination

Hereda las props de <nav>.

PropTipoPor defectoDescripción
page*number—La página actual, en base 1.
pageCount*number—Cuántas páginas hay en total. Con 0, no se renderiza nada.
aria-labelstring"Paginación"Nombre accesible del elemento.
boundariesnumber1Cuántas páginas fijas en cada punta. El mínimo real es 1: un 0 se sube a 1, porque un paginador sin la página 1 a la vista no se puede usar.
labelsPaginationLabels—Textos de la interfaz, para traducir o ajustar el tono.
onPageChange(page: number) => void—Modo botones: se llama con la página destino.
render(page: number) => RenderElement—Modo links: devuelve el elemento de cada página. Clona el elemento del llamador, así que sigue siendo un <a>.
siblingsnumber1Cuántas páginas a cada lado de la actual.
size"sm" | "md""md"sm 28px · md 36px (la escala de alto de los controles).
classNamestring—Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana.

Teclado

Tab
Recorre los controles en el orden visual. Anterior y siguiente siguen tabulables en las puntas.
Enter
Va a esa página. En un control sin destino no hace nada.

Accesibilidad

  • Es un <nav aria-label="Paginación"> con un <ul>: un lector anuncia «navegación, lista, 7 elementos».
  • Cada número tiene nombre accesible propio («Página 3»), no solo el dígito suelto.
  • La página actual lleva aria-current="page".
  • En las puntas, anterior y siguiente usan aria-disabled y no disabled: si se deshabilitaran, el foco se perdería justo después de hacer click. Es la misma decisión que Button loading.
  • El «…» es role="presentation" con texto solo para lectores («Más páginas»).
  • Sin "use client": en modo links los <a> salen en el HTML del server.

Reglas de uso

  • Si la página vive en la URL, `render`: render={(page) => <Link href={?page=${page}} />}. Son <a> de verdad, así que el crawler los ve, se abren en una pestaña nueva y se puede copiar el link.
  • `onPageChange` solo para una lista que se pagina sin cambiar de URL. Si al recargar volvés a la página 1, elegiste mal.
  • Qué páginas mostrar es una función pura: paginationRange (sebs7n-ui/lib/pagination). Si necesitás el mismo cálculo en otro lado —un resumen «4 de 27»—, llamala, no la copies.
  • El ancho no salta al cambiar de página: cuando un «…» desaparece, lo reemplaza un número.
  • Para una lista infinita o un scroll continuo esto no sirve: hace falta saber cuántas páginas hay.

Relacionados