Skip to content

BasePagination ​

Divide uma lista longa em páginas e diz quais registros estão na tela. Use no rodapé de tabelas e listas com mais de uma página de resultados.

Uso ​

  • total é o número de registros da lista inteira, não só da página.
  • O texto "11–20 de 95" mostra o primeiro e o último registro da página e o total. Quando a página muda, o leitor de tela anuncia "Página 2 de 10, registros 11 a 20 de 95". Com a lista vazia, aparece "Nenhum registro".
  • Com até 7 páginas, todas aparecem. Acima disso, a primeira, a última e as vizinhas da atual ficam visíveis, e o resto vira "…". A barra mantém a mesma largura ao trocar de página.
  • Passe page-sizes para mostrar o seletor "Itens por página". Ao trocar o tamanho, a página muda para manter na tela o primeiro registro que o usuário estava vendo. Se page-size não estiver entre as opções, ele entra na lista para o seletor mostrar o tamanho em uso.
  • Quando um filtro reduz a lista e a página atual deixa de existir, o componente corrige a página para a última e emite update:page. Com v-model:page, a tela busca a página certa sem código extra. A correção espera a lista ter registros e o disabled sair: com total igual a 0 (antes da primeira busca, por exemplo), a página pedida num link direto é mantida.
  • Em telas de celular (até 575 px), aparecem só a página atual e os botões "Página anterior" e "Próxima página".
  • Com duas paginações na mesma tela (acima e abaixo da tabela), dê um label diferente a cada uma e passe silent na segunda, para o leitor de tela não anunciar a mesma troca duas vezes.
  • Quando a lista cabe numa página só, a paginação pode ser omitida.

Anatomia ​

  1. Itens por página: o seletor com rótulo visível, que só aparece com page-sizes.
  2. Intervalo: o texto "11–20 de 95", calculado de total, da página e do tamanho da página.
  3. Página anterior e Próxima página: botões só com ícone, nas pontas da lista.
  4. Páginas: um botão para cada número, com a página atual preenchida e sublinhada. As reticências "…" ficam no lugar das páginas escondidas.

Muitas páginas ​

Com seletor de itens por página ​

Estados ​

Na primeira página, "Página anterior" fica esmaecido; na última, "Próxima página". Os dois continuam no foco do teclado, para o usuário não perder o lugar ao chegar no fim. disabled trava os controles, por exemplo enquanto a lista recarrega: os botões e o seletor ficam esmaecidos e ignoram cliques e trocas, mas o foco continua no controle que o usuário acabou de acionar.

Tamanhos ​

Use sm (32 px) no rodapé de tabelas densas, md (40 px) no padrão e lg (48 px) em telas de toque.

Faça e não faça ​

FaçaNão faça
Passe em total o número de processos da lista inteiraPassar só a quantidade de processos da página atual
Ligue disabled enquanto a próxima página de contratos carregaEsconder a paginação durante a carga, que tira o foco de quem usa teclado
Com paginação acima e abaixo da tabela, dê label diferente e silent na segundaDeixar as duas anunciarem a mesma troca

Estilo ​

PropriedadeToken
Página atualFundo --tj-background-inverse, texto --tj-text-inverse, semibold e sublinhado de 2 px
Outras páginasTexto --tj-text-secondary, hover --tj-layer-accent-01, pressionado --tj-layer-accent-02
Reticências--tj-text-helper
Botões inativos (extremos e disabled)--tj-icon-secondary
Seletor com disabledFundo --tj-field-disabled, texto --tj-icon-secondary, borda --tj-border-subtle-02
Texto do intervalo--tj-text-helper, 13 px, algarismos tabulares
FocoContorno de 2 px em --tj-border-interactive, afastado 2 px (botões); --tj-ring no seletor
Raio--tj-radius-md (8 px)
Altura--tj-control-sm/md/lg (32, 40, 48 px)
Espaço entre botões--tj-space-1 (4 px)

Código ​

vue
<BasePagination
  v-model:page="page"
  v-model:page-size="pageSize"
  :total="contractCount"
  :page-sizes="[10, 25, 50]"
  label="Páginas de contratos"
/>

Propriedades ​

Propriedade Tipo Padrão Descrição
totalnumberobrigatóriaRegistros da lista inteira
pageSizesreadonly number[]—Opções do seletor "Itens por página"; sem ele, o seletor não aparece
size'sm' | 'md' | 'lg''md'Altura dos botões e do seletor
disabledbooleanfalseTrava os botões e o seletor com aria-disabled, sem tirar o foco deles; a correção de página fica para depois
labelstring'Paginação'Nome da região de navegação; mude quando a tela tiver mais de uma paginação
silentbooleanfalsePara de anunciar o intervalo ao leitor de tela; use na segunda paginação da tela
v-model:pagenumber1Página atual, começando em 1
v-model:page-sizenumber10Registros por página

Eventos: update:page e update:pageSize. Uma página fora do intervalo válido é corrigida para a mais próxima (a última, se estiver acima) e o componente emite update:page com ela. Com total igual a 0 ou com disabled, a página fica como está e nada é emitido.

Acessibilidade ​

  • Segue o padrão de marcos (landmarks) do WAI-ARIA APG, no marco de navegação: um <nav> com aria-label="Paginação" e a lista de páginas em <ul>.
  • Cada página é um <button> nativo com nome "Página 3". Tab percorre os botões; Enter e Espaço acionam.
  • A página atual tem aria-current="page". A cor não é o único sinal: o número fica sublinhado, além do fundo preenchido e do peso semibold. No modo de alto contraste do Windows, ela ganha borda na cor de destaque do sistema.
  • "Página anterior" e "Próxima página" são botões só com ícone; o nome vem do label e aparece também como dica do mouse.
  • Nos extremos e com disabled, os botões e o seletor recebem aria-disabled="true" em vez de disabled, para o foco não sumir ao chegar na última página nem enquanto a lista recarrega. Com disabled, o seletor continua recebendo o foco, mas ignora as teclas que abririam a lista ou trocariam o valor, e o clique do mouse não abre a lista. Se uma troca passar mesmo assim, ela é desfeita e não emite nada.
  • Teclado:
TeclaO que faz
Tab / Shift + TabPassa pelo seletor "Itens por página", por "Página anterior", pelas páginas e por "Próxima página". Os botões inativos continuam na ordem
Enter / EspaçoNum botão, vai para a página. Num botão inativo, não faz nada
↑ / ↓ / ← / → / Home / End / Page Up / Page Down / letrasNo seletor, trocam o tamanho da página, como num seletor nativo. Com disabled, são ignoradas
Alt + ↓ / Enter / EspaçoNo seletor, abrem a lista de tamanhos, conforme o navegador. Com disabled, são ignoradas
  • Botões inativos usam --tj-icon-secondary, abaixo de 4,5:1. A WCAG 1.4.3 isenta componentes inativos do contraste mínimo, e o estado chega ao leitor de tela pelo aria-disabled. Para quem enxerga, o sinal de inativo é só a cor, como no BaseButton desabilitado, que não usa opacidade: a WCAG 1.4.1 foi considerada e a escolha é deliberada, porque o estado inativo não é informação que o usuário precise ler para agir.
  • O foco dos botões é um contorno sólido em --tj-border-interactive, não o --tj-ring translúcido, que fica abaixo de 3:1 sobre o fundo da página (WCAG 1.4.11).
  • O intervalo fica numa região aria-live="polite" com aria-atomic="true": depois de cada troca, o leitor de tela anuncia a frase inteira, "Página 2 de 10, registros 11 a 20 de 95". Essa frase é só para leitores de tela; o texto visível "11–20 de 95" fica com aria-hidden, porque o NVDA não fala o travessão no nível de pontuação padrão.
  • Os itens de reticências ficam fora da árvore de acessibilidade (aria-hidden no <li>), então a lista anuncia só as páginas reais.
  • No modo de alto contraste do Windows, o foco vira contorno na cor de destaque do sistema, já que o anel com box-shadow some.
  • O seletor de itens por página tem <label> visível ligado a ele.
  • A transição de cor e o deslocamento ao pressionar "Página anterior" e "Próxima página" somem com prefers-reduced-motion. Funciona nos temas claro e escuro.
  • Testado com axe nos estados que o jsdom cobre: primeira, meio, perto do fim e última página, lista vazia (com e sem seletor), poucas páginas, com seletor (inclusive com tamanho fora das opções), disabled na primeira, no meio e na última página, label próprio, tamanhos sm e lg com seletor, silent e duas paginações na mesma tela. O layout compacto de celular e o modo de alto contraste dependem de CSS e são conferidos visualmente.