KDS
Navigation

Pagination

Navegação por páginas com URLs estáveis — para deep linking e bookmarking.

Overview

Pagination divide listas longas em páginas navegáveis com URLs estáveis. É a escolha certa quando os usuários precisam voltar exatamente ao mesmo lugar — listas de pesquisa, results de admin, artigos de um blog, paginated APIs.

A decisão entre Pagination, infinite scroll e load-more é uma escolha de commitment do usuário:

Quando o usuário precisa…Use
Bookmarkar e compartilhar uma posiçãoPagination
Explorar sem fim e sem comprometimentoInfinite scroll
Carregar mais sob demanda mas chegar ao footerLoad-more
Preview
Numérica + Previous/Next na primeira posição.

Anatomy

<Pagination>
  <PaginationContent>
    <PaginationItem><PaginationPrevious /></PaginationItem>
    <PaginationItem><PaginationLink /></PaginationItem>
    <PaginationItem><PaginationEllipsis /></PaginationItem>
    <PaginationItem><PaginationLink isActive /></PaginationItem>
    <PaginationItem><PaginationNext /></PaginationItem>
  </PaginationContent>
</Pagination>

A Pagination do KDS é totalmente stateless — não gerencia qual é a página atual nem dispara fetches. O consumidor renderiza o range correto, marca isActive na atual, e desabilita Previous/Next quando aplicável.

Subcomponents

ComponenteDescrição
Pagination<nav aria-label="pagination">.
PaginationContent<ul> que organiza os itens.
PaginationItem<li> — um nó por link/ellipsis.
PaginationLinkLink de página numerada; suporta isActive.
PaginationPreviousLink "Previous" com chevron à esquerda.
PaginationNextLink "Next" com chevron à direita.
PaginationEllipsisEspaço visual quando há páginas omitidas.

Usage

import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious
} from "@kalvner/kds/navigation/pagination";

export function ListPager({ page, total }: { page: number; total: number }) {
  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious href={`?page=${page - 1}`} />
        </PaginationItem>
        {Array.from({ length: total }).map((_, i) => (
          <PaginationItem key={i}>
            <PaginationLink href={`?page=${i + 1}`} isActive={i + 1 === page}>
              {i + 1}
            </PaginationLink>
          </PaginationItem>
        ))}
        <PaginationItem>
          <PaginationNext href={`?page=${page + 1}`} />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}

Variants

With ellipses
Para totais grandes — mostra extremos + página atual.

States

At first page
Previous desabilitado via aria + opacity.
At last page
Next desabilitado simétrico.

Composition

Data table footer
Range textual à esquerda, paginator à direita.

Mostrando 21–30 de 142 resultados

When to use

  • Listas com ordem estável que se beneficiam de URLs bookmarkáveis (search results, admin tables, blog index).
  • Quando o usuário precisa pular para o final ou para uma página específica diretamente.
  • Para SEO — cada página deve ter URL própria (?page=N).

When not to use

  • Feeds sociais ou exploração descomprometida — use infinite scroll.
  • Quando o total é desconhecido até carregar (use load-more).
  • Em listas curtas (≤25 itens) — não pagine.
  • Para conteúdo extremamente dinâmico onde a posição muda a cada segundo.

Best practices

  • URLs reais sempre. Use href="?page=2" em vez de onClick
    • state. Garante refresh, share, back/forward, deep-linking.
  • Desabilite com aria. Em Previous/Next nos extremos, aplique aria-disabled="true" + tabIndex={-1} + pointer-events-none.
  • Range textual de apoio. "Mostrando 21–30 de 142" responde perguntas que numeração não responde.
  • Page size selector é Forms. O <select> para escolher quantidade por página é um Combobox/Select separado, fora do Pagination.
  • Mobile compacta. Em telas estreitas, mostre apenas Previous/Next + indicador de página atual.

Accessibility

ConcernComportamento
Roles<nav aria-label="pagination">.
Current pageLink ativo recebe aria-current="page".
Disabled stateAplique aria-disabled="true" + tabIndex={-1} + classes que removem pointer events. Não use atributo HTML disabled em <a>.
KeyboardTab navega normalmente entre os links visíveis.
Screen readerAnunciado como "navigation, pagination" + número da página atual.
  • Breadcrumb — orientação hierárquica, não paginação.
  • Tabs — alternar views, não paginar listas.

On this page