# Pagination

> Componentes / Navegação e estrutura · Estado: **Em andamento** — Implementado e utilizável, mas ainda sem a validação completa de acessibilidade.

Paginação de lista: anterior, os números das páginas (com reticências quando são muitas) e próxima. Com `hrefDaPagina`, cada página é um link com endereço (E71); sem, são botões que trocam no lugar. No celular, os números dão lugar a "Página X de Y".

- Função: Navegação e estrutura
- Também chamado de: paginação, páginas, anterior e próxima
- Mora em: `app/components/molecules/Pagination.tsx`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/Pagination](https://phorte-design-system.vercel.app/styleguide/peca/Pagination)
- Ficha no Storybook: [components-complex-pagination](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-complex-pagination--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/Pagination/0](https://phorte-design-system.vercel.app/previa/Pagination/0)
- Todas as peças: [https://phorte-design-system.vercel.app/llms.txt](https://phorte-design-system.vercel.app/llms.txt)

## Como usar no código

```tsx
import { Pagination } from '@/app/components/molecules/Pagination';

<Pagination currentPage={…} totalPages={…}>…</Pagination>
```

O `…` marca as props obrigatórias — ver *Propriedades*.

## Uso

### Variantes na ficha

1. [Padrão](https://phorte-design-system.vercel.app/previa/Pagination/0)
2. [Muitas Paginas](https://phorte-design-system.vercel.app/previa/Pagination/1)
3. [Interativo](https://phorte-design-system.vercel.app/previa/Pagination/2)
4. [Com endereço](https://phorte-design-system.vercel.app/previa/Pagination/3)

Embaixo de uma lista ou grade longa dividida em páginas — resultados de busca, catálogo de cursos, posts do blog.

### Quando não usar

Para passar itens de um carrossel, use o CarouselNavButton. Para alternar seções de uma página, o CourseTabs.

### Faça

- Com mais de uma paginação na página, dê a cada uma um nome próprio: `aria-label="Paginação dos resultados de busca"` substitui o padrão "Paginação" (E143, Magoo).
- Na troca no lugar (`onPageChange`), anuncie o trecho novo numa região viva ("Página 3 de 12") e deixe o foco no controle: a Pagination não sabe o que mudou na lista.
- Use `hrefDaPagina` quando a lista tem endereço (o catálogo): a página 2 vira link indexável, compartilhável e que abre em nova aba (E71).
- Para lista que troca no lugar, guarde a página no consumidor e passe `currentPage`; `onPageChange` recebe a escolhida.
- Leve o foco (ou a rolagem) ao início da lista depois de trocar de página.
- Dê um `aria-label` próprio quando houver duas paginações na tela.

### Evite

- Contar com os números no celular: abaixo de 768px, só anterior, próxima e o texto "Página X de Y" aparecem.

### Anatomia

1. **Anterior** — "Página anterior"; indisponível na primeira.
2. **Números** — Até sete, com `aria-label` "Página N de T"; o atual em vermelho.
3. **Reticências** — Marcam os saltos quando há mais de sete páginas; decorativas.
4. **Texto compacto** — "Página X de Y", só abaixo de 768px.
5. **Próxima** — "Próxima página"; indisponível na última.

### Estados

| Estado | O que muda |
| --- | --- |
| Página atual | Fundo `--primary`, texto branco e `aria-current="page"`. |
| Outra página | Borda e texto escuro; no hover, fundo `--muted`. |
| Foco | O anel de foco, só no teclado. |
| Ponta, em botões | Anterior (na primeira) ou próxima (na última) a 50%, com `aria-disabled="true"`: continua no Tab, o leitor diz "indisponível" e o clique não faz nada. |
| Ponta, em links | Sem destino, fica só o desenho a 50%, fora do Tab e da árvore — conferido no teste da ficha. |

### Comportamento

| Situação | O que acontece |
| --- | --- |
| Uma página só | Não renderiza nada (E71) — conferido no teste da ficha. |
| Página fora do intervalo | Fica presa nele: `currentPage={40}` de 5 vira a 5 (E71) — conferido no teste da ficha. |
| Até sete páginas | Todas aparecem. |
| Mais de sete, perto do começo | 1 a 5, reticências e a última. |
| Mais de sete, no meio | A primeira, reticências, a atual com as vizinhas, reticências e a última. |
| Tela abaixo de 768px | Os números e as reticências somem; aparece "Página X de Y". |

### Relacionados

- [CarouselNavButton](https://phorte-design-system.vercel.app/styleguide/md/CarouselNavButton.md) — Anterior e próximo de um carrossel.
- [CourseTabs](https://phorte-design-system.vercel.app/styleguide/md/CourseTabs.md) — Para alternar seções de uma página.

## Especificação

### Propriedades

| Prop | Tipo | Padrão | Obrigatória | Descrição |
| --- | --- | --- | --- | --- |
| `currentPage` | `number` | — | sim |  |
| `totalPages` | `number` | — | sim |  |
| `onPageChange` | `(page: number) => void` | — | não | Lista no cliente: troca a página sem mudar de endereço. |
| `hrefDaPagina` | `(page: number) => string` | — | não | Página com URL (E71): `(p) => '/cursos?pagina=' + p`. Com ele, cada número é um link — indexável, compartilhável, abre em nova aba. O catálogo de uma faculdade precisa disso; o `onPageChange` continua para lista que troca no lugar. |

Aceita também: `Omit<React.HTMLAttributes<HTMLElement>, 'onChange'>`.

### Medidas

| Parte | Valor | Classe |
| --- | --- | --- |
| Cada controle | 44 × 44px | `w-alvo-toque h-alvo-toque` |

### Tokens de cor

| Token | Valor | Usado como |
| --- | --- | --- |
| `--primary` | #D42B2B | `bg-primary`, `border-primary` |
| `--border` | #E5E5E5 | `border-border` |
| `--border-interactive` | #8C8C8C | `border-border-interactive` |
| `--foreground` | #1A1A1A | `text-ink` |
| `--muted` | #F4F6F9 | `bg-muted` |
| `--muted-foreground` | #595959 | `text-muted-foreground` |
| `--primary-foreground` | #FFFFFF | `text-primary-foreground` |

## Acessibilidade

### Teclado

| Tecla | Faz |
| --- | --- |
| Tab | Passa por anterior, pelos números visíveis e por próxima; em botões, as setas das pontas também, indisponíveis. No celular, só anterior e próxima. |
| Enter / Espaço | Em botões, vai à página em foco; ela passa a ter `aria-current="page"` — conferido no teste da ficha. Em links, só o Enter, que segue o endereço. |

### Leitor de tela

- É uma `<nav>` "Paginação"; cada número é lido como "Página 3 de 10".
- Em botões, as setas das pontas usam `aria-disabled`, e não `disabled`: desabilitar o botão com o foco em cima jogava o foco no `<body>` (E102).
- As reticências são `aria-hidden`.

### O que sustenta o estado

Usa os padrões: navegacao. Falta ouvir com leitor de tela: navegacao.

## Status e recursos

| Tipo | Recurso | Status |
| --- | --- | --- |
| Código | `app/components/molecules/Pagination.tsx` | Disponível |
| Ficha | https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-complex-pagination--docs | Disponível |
| Teste de acessibilidade | axe em `npm run test` | No gate de todo commit |
| Leitor de tela | Passada da E33 | Falta ouvir |
| Design | Figma | Desativado até a Fase 2 |

### Histórico

- `251416b` 2026-10-01 — E159: Testimonials — o vídeo toca dentro do cartão, YouTube e Vimeo
- Histórico completo no GitHub: https://github.com/srbunnie/Pos-Phorte-Design-System/commits/main/app/components/molecules/Pagination.tsx
