Accordion e abas acessíveis em JavaScript: código para copiar e colar | We.Inc
Um accordion em JavaScript puro com altura animada e aria-expanded, e abas com teclas de seta e roving tabindex. Os dois rodam ao vivo na página, com um checklist de teclado e uma tabela de ARIA.
Um accordion acessível usa um botão de verdade dentro de cada título, com aria-expanded indicando se o painel está aberto e aria-controls apontando o painel. Abas acessíveis usam role=tablist, tab e tabpanel, com aria-selected, e passam de uma aba para outra com as teclas de seta, mantendo só a aba selecionada na ordem do Tab. As duas demos abaixo rodam ao vivo.
Qual usar
Use
Quando
Accordion
Páginas longas de perguntas, em que as pessoas podem ler várias respostas
Abas
Algumas visões da mesma coisa, lidas uma de cada vez
details e summary
Mostrar e esconder simples, sem nenhum JavaScript
Cada demo é um único bloco autossuficiente de HTML, CSS e JavaScript. Edite e o resultado roda de novo. Depois deixe o mouse de lado e teste com o teclado usando o checklist mais abaixo.
Copie para a sua página o bloco do componente de que você precisa.
Altere o texto, mantendo cada id único na página.
Teste com o teclado: Tab, Enter, Space, as setas, Home e End.
Teste com um leitor de tela: ele deve dizer expandido ou recolhido, ou aba 2 de 3.
Confira a página com o movimento reduzido ativado; os painéis devem abrir sem animação.
Mantenha o botão dentro do título em vez de tornar o título clicável; títulos não recebem foco e não anunciam estado.
Use o atributo hidden nos painéis fechados para que os links deles não possam ser alcançados com Tab.
Não coloque abas dentro de abas nem accordions dentro de abas; as pessoas perdem a noção de onde estão.
Se as respostas importam para a busca, deixe-as no HTML (escondidas, não carregadas depois) para que robôs de busca e pessoas vejam o mesmo texto.
Perguntas frequentes
As abas devem mudar com a tecla de seta ou com Enter?
O guia de ARIA permite as duas formas. Mudar conforme a seta se move (ativação automática) parece mais rápido quando os painéis já estão carregados. Se exibir um painel for lento, mova o foco com as setas e mude com Enter ou Space.
Como animo a altura de um accordion sem medir com JavaScript?
Transforme o painel em uma grid e faça a transição de grid-template-rows de 0fr para 1fr, com um elemento interno com overflow hidden. O navegador calcula a altura para você.
O elemento details é acessível?
Sim. Os navegadores expõem o summary como um botão com estado de expandido, e ele funciona com o teclado sem configuração. Estilizar o marcador e animá-lo é mais difícil, e é por isso que muitos sites ainda criam o próprio.
Respostas escondidas em accordion contam para SEO?
Conteúdo que está no HTML, mas recolhido, ainda é rastreado. Mantenha-o no código-fonte da página em vez de carregá-lo no clique, e garanta que a resposta visível corresponda ao que está no HTML.
Próximos passos
Se você trabalha com React, a nossa galeria de componentes tem um conjunto de abas com sublinhado deslizante e um accordion de FAQ, ambos com JSX para copiar. Para uma seção de FAQ, adicione dados estruturados FAQPage correspondentes só se as perguntas e respostas estiverem visíveis na página.
Erros comuns
Usar elementos div com handlers de clique como cabeçalhos do accordion. Eles não podem ser alcançados com Tab, e os leitores de tela não sabem que fazem alguma coisa.
Colocar todas as abas na ordem do Tab, o que obriga quem usa teclado a passar por todas elas para chegar ao conteúdo.
Esquecer de atualizar aria-expanded ou aria-selected quando o estado muda, fazendo o leitor de tela informar a coisa errada.
Accordion
Accordion acessível com altura animada
Cada título contém um botão de verdade com aria-expanded e aria-controls. A altura é animada com uma transição de grid-rows, então não é preciso medir scrollHeight. Experimente com Tab, Enter e Space.
Só um painel aberto por vez
Quando um painel abre, feche qualquer outro que esteja aberto. Deixe isso opcional: quem está comparando duas respostas muitas vezes quer as duas abertas.
Fallback sem JavaScript: details e summary
Elementos details nativos abrem e fecham sem script. Dar a eles o mesmo atributo name os torna exclusivos nos navegadores atuais; os mais antigos apenas permitem vários abertos.
Abas
Abas com roving tabindex e teclas de seta
Só a aba selecionada tem tabindex 0, então o Tab entra na lista de abas uma vez e depois segue para o painel. As setas para a esquerda e para a direita passam de uma aba para outra, Home e End pulam para as pontas.
Checklist de teclado e ARIA
Teste de teclado: experimente cada um nas demos
Tecla
Accordion
Abas
Tab
Vai para o próximo botão de cabeçalho
Entra na lista de abas pela aba selecionada e depois vai para o painel
Shift + Tab
Vai para o botão de cabeçalho anterior
Sai de volta da lista de abas
Enter ou Space
Abre ou fecha o painel em foco
Seleciona a aba em foco (necessário só com ativação manual)
Seta para a direita / esquerda
Não é necessário
Próxima / aba anterior, voltando ao início no fim
Home / End
Opcional: primeiro / último cabeçalho
Primeira / última aba
Referência de ARIA
Atributos de que cada parte precisa
Elemento
Accordion
Abas
Gatilho
button dentro de um título, aria-expanded, aria-controls
role=tab, aria-selected, aria-controls, tabindex 0 ou -1
Container
Nenhum obrigatório
role=tablist com aria-label
Painel
id; role=region com aria-labelledby é opcional
role=tabpanel, aria-labelledby, tabindex 0 se não tiver conteúdo focável