Abas parecem simples porque exibem um painel e escondem os outros. A complexidade está no foco. Uma implementação feita só com botões lado a lado costuma obrigar quem usa teclado a pressionar Tab em todas as opções. Outra pode mudar o conteúdo ao receber foco, mesmo que o painel ainda esteja carregando. Há também abas visualmente ativas que continuam com aria-selected="false".
Uma interface de abas acessível sincroniza quatro coisas: foco, seleção, painel visível e conteúdo anunciado. O conjunto precisa ter uma entrada previsível na ordem da página, responder às setas corretas e continuar compreensível quando o layout estreita. Este guia mostra quando usar o padrão, como montar sua estrutura e como testar a URL publicada.
Use abas apenas para conteúdo paralelo
Abas funcionam quando vários painéis ocupam o mesmo lugar e representam alternativas equivalentes dentro de um contexto. Exemplos incluem detalhes de um produto, demonstrações por linguagem ou visões resumidas do mesmo conjunto de dados.
Escolha outro formato quando:
- a pessoa precisa comparar os painéis ao mesmo tempo;
- o conteúdo deve ser lido em sequência;
- cada seção merece URL, título e compartilhamento próprios;
- existem tantas opções que os rótulos não cabem sem rolagem difícil;
- carregar um painel pode demorar;
- o conteúdo oculto é essencial para entender a oferta.
Uma lista, grade ou sequência de seções costuma funcionar melhor para comparação e leitura contínua. Um acordeão mantém todos os cabeçalhos na ordem normal de Tab. Abas usam navegação interna com setas e devem ter apenas um item do conjunto na sequência de Tab.
Não use details para imitar abas. O HTML Standard trata details como disclosure, não como tab widget. O comportamento de teclado e a relação entre controles e painéis são diferentes.
Modele tablist, tab e tabpanel juntos
O padrão de abas da W3C define três funções:
tablistagrupa as abas;tabrepresenta cada opção;tabpanelcontém o conteúdo associado.
Uma estrutura básica pode começar assim:
<div role="tablist" aria-label="Detalhes do plano"> <button type="button" id="aba-recursos" role="tab" aria-selected="true" aria-controls="painel-recursos" tabindex="0" > Recursos </button> <button type="button" id="aba-limites" role="tab" aria-selected="false" aria-controls="painel-limites" tabindex="-1" > Limites </button></div>
<div id="painel-recursos" role="tabpanel" aria-labelledby="aba-recursos">...</div><div id="painel-limites" role="tabpanel" aria-labelledby="aba-limites" hidden>...</div>O tablist precisa de nome quando o contexto não fica claro. Prefira aria-labelledby se já existe um título visível; use aria-label para um rótulo curto quando não houver título adequado.
Cada tab aponta para um único painel com aria-controls. Cada tabpanel aponta de volta para sua aba com aria-labelledby. IDs duplicados ou referências quebradas desmontam essa relação mesmo que a interface continue parecendo correta.
Separe foco de seleção
Foco e seleção podem coincidir, mas não significam a mesma coisa. Foco identifica qual aba recebe o próximo comando de teclado. Seleção identifica qual painel está ativo.
Use roving tabindex para manter uma única aba na sequência da página:
- a aba ativa ou o destino definido pelo produto usa
tabindex="0"; - as outras usam
tabindex="-1"; - a seta muda o
tabindexanterior para-1; - a seta muda o próximo item para
0e chamafocus(); Tabsai do conjunto em vez de visitar cada aba.
Não use valores positivos de tabindex. Eles criam uma ordem paralela ao DOM e ficam frágeis quando o conteúdo muda. A orientação da W3C sobre interfaces de teclado recomenda alinhar ordem de foco, ordem do DOM e leitura sempre que possível.
Escolha ativação automática ou manual
Na ativação automática, mover foco com a seta também seleciona a aba e exibe seu painel. Esse comportamento funciona quando o conteúdo já está disponível e a troca não tem latência perceptível.
Na ativação manual, as setas movem apenas o foco. Enter ou Espaço confirma a seleção. Prefira esse modelo quando o painel depende de rede, renderização pesada ou qualquer atraso que torne a passagem entre abas lenta.
Não misture os dois modelos. Se a primeira seta apenas foca e a segunda troca conteúdo, a interação fica impossível de prever. Documente a escolha no componente e cubra o ciclo completo em teste.
Ativar uma aba ao receber foco não deve enviar formulário, abrir página, deslocar foco para outro elemento nem iniciar uma tarefa irreversível. A seleção troca o painel do próprio componente.
Implemente as teclas conforme a orientação
Num conjunto horizontal:
Seta para a direitamove para a próxima aba;Seta para a esquerdamove para a anterior;- o movimento pode circular entre o fim e o início;
Homepode levar à primeira aba;Endpode levar à última;EntereEspaçoativam no modelo manual;Tabsai dotablistem direção ao painel ou ao próximo controle lógico.
Não intercepte Seta para cima e Seta para baixo num conjunto horizontal. O navegador precisa dessas teclas para rolar a página. Em um tablist vertical, defina aria-orientation="vertical" e use setas para cima e para baixo.
Se o painel ativo não contém nenhum elemento focável, tabindex="0" no tabpanel pode incluí-lo na sequência. Se o primeiro conteúdo significativo já é um link, botão ou campo, evite criar uma parada redundante apenas no contêiner.
O roteiro de navegação por teclado ajuda a conferir foco visível, ordem e comportamento de teclas em diferentes sistemas.
Sincronize todos os estados numa única operação
Ao selecionar uma aba, atualize o conjunto inteiro:
- defina
aria-selected="false"etabindex="-1"na aba anterior; - esconda o painel anterior;
- defina
aria-selected="true"etabindex="0"na nova aba; - revele o painel correspondente;
- mantenha o foco na aba que recebeu a ação, salvo um fluxo explicitamente definido.
Não use apenas uma classe como .active. Também não deixe dois itens selecionados ou dois painéis visíveis num padrão de seleção única. Se o estado vem de um framework, derive atributos, estilo e visibilidade da mesma fonte para reduzir desencontros.
Painéis ocultos precisam sair da apresentação visual, da árvore de acessibilidade e da ordem de foco. O atributo hidden atende ao caso simples. opacity: 0, deslocamento fora da tela ou altura zero podem deixar links ocultos alcançáveis.
O artigo sobre nomes acessíveis de links e botões ajuda a revisar rótulos repetidos, ícones e nomes que não correspondem ao texto visível.
Não transforme a troca em anúncio excessivo
O leitor de tela recebe mudanças de foco, seleção e relação com o painel. Evite adicionar aria-live ao conjunto inteiro por padrão. Uma região ao vivo pode reler conteúdo extenso a cada seta e interromper o que a pessoa já estava ouvindo.
Use rótulos curtos que diferenciem as opções. “Visão geral”, “Recursos” e “Limites” dão mais contexto do que “Aba 1”, “Aba 2” e “Aba 3”. Se os rótulos dependem de um título externo, confira a sequência anunciada no leitor de tela real.
Teste também o painel. Títulos, listas, tabelas e controles internos continuam precisando de semântica própria. tabpanel não descreve automaticamente todo o conteúdo.
Planeje URL, histórico e carregamento
Algumas abas representam um estado que merece link direto. Nesse caso, defina como a URL identifica a seleção, como o botão Voltar se comporta e qual painel aparece quando o valor é inválido.
Não use um link com destino falso apenas para obter estilo de aba. Se a interação troca conteúdo na mesma página, um botão com role="tab" costuma ser a base mais previsível. Se cada opção navega para outra URL, talvez sejam links de navegação estilizados, não abas.
Carregar o conteúdo sob demanda exige estados de espera e erro. Na ativação automática, não bloqueie cada movimento de seta com uma requisição. Pré-carregue ou use ativação manual. Preserve o painel anterior até o novo estado estar pronto e não envie o foco para um spinner sem um motivo claro.
Trate rolagem e largura estreita
Uma fileira de abas que cabe no desktop pode cortar rótulos no celular. Evite reduzir fonte e alvo até tudo caber. Considere:
- permitir quebra controlada quando a ordem continuar clara;
- usar rolagem horizontal com indicação visível de conteúdo adicional;
- trocar para uma lista de seções em larguras estreitas;
- encurtar rótulos sem perder significado;
- limitar o número de opções do conjunto.
Se o foco muda para uma aba fora da área visível, role o próprio conjunto apenas o suficiente para revelar o controle. Não mova a página de forma brusca. Confirme foco não encoberto por cabeçalhos fixos e teste zoom de 200% e 400%.
O guia de zoom e reflow ajuda a identificar corte, sobreposição e rolagem em duas dimensões. O roteiro de alvos de toque cobre tamanho e espaçamento entre rótulos próximos.
Teste o componente como uma máquina de estados
Uma captura prova apenas o estilo inicial. Monte uma matriz de estados:
| Situação | Evidência esperada |
|---|---|
entrada com Tab |
foco chega à aba ativa ou ao destino definido |
| seta seguinte | foco muda uma posição e respeita a orientação |
| ativação manual | painel muda apenas após Enter ou Espaço |
| ativação automática | painel aparece sem atraso perceptível |
| aba selecionada | estilo, aria-selected, tabindex e painel concordam |
| painel oculto | conteúdo não aparece, não é lido e não recebe foco |
| largura estreita | rótulos e foco permanecem visíveis e operáveis |
| falha de carregamento | há mensagem útil sem abandonar a posição do componente |
Repita a matriz com mouse, toque, teclado e leitor de tela. O guia de teste com leitor de tela ajuda a conferir nome, função, estado e relação sem depender apenas da árvore de acessibilidade do navegador.
Use um pedido de correção verificável
Revise as interfaces de abas desta landing page sem publicar ainda.
Escopo:- fonte e commit: [referência]- rotas: [lista]- conjuntos de abas: [inventário]
Para cada conjunto:1. Confirme se abas são o padrão adequado para o conteúdo.2. Registre tablist, tabs, tabpanels, orientação e estado inicial.3. Escolha ativação automática apenas quando os painéis estiverem prontos sem atraso.4. Implemente roving tabindex e as teclas esperadas para a orientação.5. Sincronize foco, aria-selected, painel visível e estilo ativo.6. Remova painéis ocultos da leitura e da ordem de foco.7. Teste teclado, leitor de tela, toque, zoom, URL e estados de erro.8. Preserve conteúdo, analytics e lógica de negócio.
Entregue a matriz de estados, o diff e as evidências antes de publicar.O pedido impede uma correção apenas visual. Cada mudança precisa aparecer no HTML, no teclado e na tecnologia assistiva.
Reteste a versão publicada
Depois da aprovação, siga a documentação de Publicação: publique uma nova Version, acompanhe o deploy e abra a URL final. Teste entrada, setas, seleção, saída com Tab, links internos e comportamento do histórico.
Faça o percurso depois que fontes, scripts e dados terminarem de carregar. Se a hidratação redefinir a seleção, esconder o foco ou tornar painéis inativos alcançáveis, corrija a fonte e republique o mesmo Site. As abas estão prontas quando foco, seleção e conteúdo permanecem sincronizados em toda forma de entrada.
