# Pagination

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

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

Sin `"use client"`: sirve en un Server Component.

## Ejemplos

### Con botones

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

```tsx
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>
  )
}
```

### Con links

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.

```tsx
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.

```tsx
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

### Pagination

Hereda las props de `<nav>`.

| Prop | Tipo | Por defecto | Descripció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-label` | `string` | `"Paginación"` | Nombre accesible del elemento. |
| `boundaries` | `number` | `1` | Cuá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. |
| `labels` | `PaginationLabels` | — | 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>`. |
| `siblings` | `number` | `1` | Cuántas páginas a cada lado de la actual. |
| `size` | `"sm" \| "md"` | `"md"` | `sm` 28px · `md` 36px (la escala de alto de los controles). |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

`*` obligatoria.

## Teclado

| Tecla | Qué hace |
|---|---|
| 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

[breadcrumb](/docs/components/breadcrumb.md) · [table](/docs/components/table.md) · [button](/docs/components/button.md)
