ARIA Role Button: Guia Completo e Prático
O aria role button é um rol ARIA que faz com que as tecnologias de assistência anunciem um contêiner genérico como botão, mas não aporta o comportamento: é necessário adicionar tabindex="0", gerenciar Enter e Espaço e refletir o estado com aria-pressed ou aria-disabled. A especificação WAI-ARIA 1.2 define esta função dentro da categoria de widget, e a primeira regra da ARIA recomenda usar um <button> nativo sempre que possível.
O aria role button pertence à taxonomia de papéis do WAI-ARIA, o padrão do W3C que descreve a semântica acessível para interfaces web. Quando um elemento recebe role="button", a árvore de acessibilidade que constrói os leitores de tela (NVDA, JAWS, VoiceOver, Narrator) deixa de expô-lo como um div ou um span genérico e apresentá-lo como um controle acionável. A diferença é enorme para quem navega com o leitor de tela: sem o papel, o usuário ouve “grupo” ou simplesmente texto; com o papel, ouve “botão” e sabe que pode ativá-lo.
A confusão habitual é acreditar que role="button" converte um div em um botão funcional. Não converte. O papel apenas muda a semântica anunciada; o comportamento —receber foco, responder ao teclado, disparar a ação— continua sendo responsabilidade do desenvolvedor. Esta separação entre semântica e comportamento é a causa da maioria dos erros que ocorrem neste papel.
WAI-ARIA foi publicada como recomendação do W3C e sua versão 1.2 é a referência vigente para funções, estados e propriedades. A função button é uma das funções de widget mais antigas e estabelecidas de acordo com a especificação, presente desde ARIA 1.0.
Quando usar role=“button” e quando não
A primeira regra de ARIA, reconhecida nas práticas de autoria de WAI-ARIA (Práticas de Autoria WAI-ARIA), é importante: se existir um elemento HTML nativo com a semântica e o comportamento que você precisa, use-o. <button> ya trae o rol implícito, o foco do teclado, a ativação com Enter e Espaço, e o estado desabilitado. Reimplementar tudo isso com a ária role role="button" é trabalho extra e fonte de bugs.
Existem, sem embargo, cenários legítimos para o papel. O mais comum é quando o marcador está condicionado pela estrutura ou pelo CMS e não é possível introduzir um <button> sem quebrar o layout ou o JavaScript existente. Outro caso são os componentes que devem se comportar como botão, mas cuja estrutura interna exige um contêiner específico, como certos widgets de terceiros.
Relacionado: — com plano gratuito para começar hoje mesmo.
Um terceiro cenário, mais discutível, é o elemento que você tem um papel nativo distinto e precisa ser apresentado como um botão. Aqui estou convencido de que o projeto não está forçando um equívoco semântico. Se algo parece um botão, mas na realidade navegue para outra página, o correto é um link <a>, não um botão.
| Situação | Solução recomendada | Motivo |
|---|---|---|
| Ação em formulário ou interface | <botão> nativo | Rol, foco e teclado incluídos |
| Navegação para outro URL | <a href> | Semântica de link correto |
| Contenedor não modificável | role="botão" + teclado + estados | Único caso onde o papel aporta |
| Botão de alternância (ligar/desligar) | <button aria-pressed> | Estado exposto nativamente |
| Botão desativado | <button disabled> | Estado e foco gerenciados |
Como implementar um botão com role=“button” corretamente
Um botão baseado em role="button" precisa cobrir quatro frentes: foco, teclado, estado e nome acessível. Omitir qualquer um deles produz um controle que “parece” acessível, mas falha em testes reais.
O foco é habilitado com tabindex="0", que insere o elemento na ordem de tabulação natural. Nunca usa tabindex com valores positivos: altera a ordem de tabulação de toda a página e gera saltos impredecíveis. O valor 0 é o correto para elementos interativos personalizados.
Vale a pena dar uma olhada: — Acessibilidade gerenciada: automatização combinada com revisão humana.
O teclado requer o gerenciamento das teclas: Enter e Espaço. Um <button> nativo responde a ambos, mas um div com uma função de botão ária não o faz por si só. Você deve ouvir keydown e executar a ação quando a tecla é Enter ou Space, evitando também o deslocamento de página que provoca Espaço por defeito. Este detalhe é passado por alto com frequência e deixa os botões que só funcionam com mouse.
O estado é comunicado com atributos ARIA. Um botão de alternância usa aria-pressed="true" ou "false" para indicar se está ativo. Um botão desativado usa aria-disabled="true", que indica o estado, mas não impede a interação por si só: há que bloquear a ação no código. A diferença entre aria-disabled e o atributo nativo disabled é importante, porque o primeiro mantém o elemento enfocable e o segundo o remove da ordem de tabulação.
O nome acessível é construído com o texto visível do elemento o, se não houver texto, com aria-label ou aria-labelledby. Um botão sem nome acessível é um botão que o leitor de tela anuncia como “botão” puramente, sem pista do que faz.
<div
role="botão"
tabindex="0"
aria-pressed="false"
id="btn-modo"
>
Modo escuro
</div>
<script>
const btn = document.getElementById('btn-modo');
function toggle() {
const ativo = btn.getAttribute('aria-pressed') === 'true';
btn.setAttribute('aria-pressionado', String(!activo));
}
btn.addEventListener('click', alternar);
btn.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
alternar();
}
});
</script>
O exemplo anterior cobre foco, teclado, estado e nome. É o mínimo viável para que o controle possa ser usado com o leitor de tela e o teclado.
Erros frequentes e como detectá-los
O erro mais estendido é aplicar role="button" sem tabindex, que produz um botão inalcançável no teclado. As ferramentas automáticas são detectadas como “elemento com função interativa não focalizável”, uma das violações mais relatadas em auditorias de acessibilidade.
O segundo erro não permite gerenciar o teclado. Um div com uma função de botão ária e tabindex, mas sem manejadores de tecla recebem foco e não respondem a Enter nem Espaço. O usuário do teclado fica preso: você pode focar o botão, mas não ativá-lo.
Relacionado: — A que acredita sua experiência e acessibilidade.
O terceiro erro é usar role="button" em um link. Isso rompe a semântica de navegação e confunde os leitores de tela, que anunciam um “botão” quando o usuário espera um link. Se o elemento navegar, deverá ser um link.
O quarto erro é esquecer o estado nos botões de alternância. Um botão que muda entre os modos sem aria-pressionado deixa o usuário sem saber em que estado ele se encontra. O atributo é a única forma de comunicação e esse estado de forma programática.
Para detectar esses problemas, as ferramentas automáticas como axe, Lighthouse ou WAVE sinalizam violações de rol e foco, mas não validam o comportamento do teclado nem a lógica de estado. Essa parte exige teste manual: navegue com Tab, ative com Enter e Espacio e ouça a saída do leitor de tela. A combinação de auditoria automática e teste manual é a única forma confiável de validar um botão personalizado.
Como testar um botão com role=“button”
O teste começa pelo teclado. Corrija a página com Tab e verifique se o botão com o botão Aria Role recebe o foco visível. Pulsa Enter e Espaço por separado: ambos devem disparar a ação. Se o Espacio mudar a página em vez de ativar o botão, falta o preventDefault.
A segunda tentativa é com o leitor de tela. NVDA no Windows, VoiceOver no macOS e Narrator no Windows são as referências mais usadas. Ao focar o botão, o leitor deve anunciar o rol (“botão”), o nome acessível e o estado se o tiver. Se anuncia “grupo” ou não menciona o estado, algo falha.
A terceira tentativa é a ordem de foco. O botão deve aparecer na ordem lógica de tabulação, nem antes nem depois de onde corresponde visualmente. Os tabindex positivos rompem esta ordem e são um indicador claro de má implementação.
A quarta prova é de contraste e foco visível. O indicador de foco não deve ser removido com outline: none sem substituí-lo por uma alternativa visível. Um botão que recebeu foco, mas não mostra o usuário do teclado sem referência de onde está.
Alternativas modernas ao botão rol
O elemento <button> nativo continua sendo a melhor opção em 2024 e em qualquer projeto novo. Aporta rol, foco, teclado e estados sem código adicional, e os navegadores o tratam de forma consistente.
Os elementos personalizados ou Web Components são oferecidos de outra maneira. Um componente que estende HTMLElement pode encapsular o comportamento do botão e expô-lo com a semântica correta, mas requer gerenciamento manual do foco e do teclado igual ao role="button". A venda é a reutilização; a desventaja, a mesma responsabilidade de implementação.
Las ARIA in HTML (regras que definem quais papéis ARIA são permitidos sobre cada elemento HTML) desaconsejan sobrescrever papéis nativos. Aplicar a ária role role="button" em um <button> é redundante; aplique-o a um <a> com href é contraproducente. A recomendação geral é reservar o papel para contêineres sem semântica própria.
Principais conclusões
role="button"muda apenas a semântica anunciada; o foco, o teclado e o estado são implementados manualmente.- A primeira regra da ARIA recomenda usar
<button>nativo sempre que o marcado permitir. - Um botão com ária role button necessário
tabindex="0", gerenciamento de Enter e Espaço, nome acessível e estado comaria-pressionadoouaria-disabled. - As ferramentas automáticas detectam falta de foco, mas o comportamento do teclado e o estado exigem que você verifique o manual com o leitor de tela.
- Nunca use
tabindexpositivo nem apliquerole="button"em links que navegam.
Perguntas frequentes
Qual é a diferença entre role=“button” e o elemento button?
O elemento <button> nativo inclui a função implícita, o foco do teclado, a ativação com Enter e Espaço e o estado desativado sem código adicional. O atributo role="button" apenas traz a semântica anunciada; o resto do comportamento deve ser programado. Por isso, a primeira regra da ARIA recomenda o elemento nativo sempre que for possível.
Você precisa de tabindex com role=“button”?
Si. Um div ou span com role="button" não é enfocado por defeito, assim como tabindex="0" fica fora da ordem de tabulação e é inalcançável com o teclado. O valor correto é 0; Os valores positivos alteram a ordem de tabulação de toda a página e devem ser evitados.
Como foi que uma div com role=“button” responde a Enter e Espaço?
Você deve ouvir o evento keydown e executar a ação quando a tecla for Enter ou Space. No caso do Espacio, convém chamar preventDefault para evitar o deslocamento da página. Sem esses manipuladores, o botão recebe foco, mas não é ativado com o teclado.
Como é que um botão está ativo ou desativado?
Para um botão de alternância, use aria-pressed="true" ou "false" dependendo do estado. Para um botão desativado, use aria-disabled="true", que indica o estado, mas não bloqueia a interação por si só: isso impede a ação no código. O atributo nativo disabled é preferível quando um <button> é usado.
É difícil usar role=“button” em um link?
Sim, quando o link navega para outro URL. Sobrescreva o papel de um <a href> com role="button" rompe a semântica de navegação e confunda os leitores de tela, que anunciam “botão” quando o usuário espera um link. Se o elemento navegar, você deve manter a rolagem do link.
O que as ferramentas detectaram erros com role=“button”?
Ferramentas automáticas como axe, Lighthouse ou WAVE sinalizam violações como falta de foco em elementos com função interativa. No entanto, o comportamento do teclado não é válido nem a lógica de estado, portanto a verificação confiável combina a audição automática com a verificação manual usando NVDA, VoiceOver ou Narrator.
Perguntas frequentes
Qual é a diferença entre role='button' e o elemento button?
O elemento <button> nativo inclui a função implícita, o foco do teclado, a ativação com Enter e Espaço e o estado desativado sem código adicional. O atributo role='button' apenas indica a semântica anunciada; o resto do comportamento deve ser programado. Por isso, a primeira regra da ARIA recomenda o elemento nativo sempre que for possível.
Você precisa de tabindex com role='button'?
Si. Uma div ou span com role='button' não é enfocada por defeito, assim como sin tabindex='0' fica fora da ordem de tabulação e é inalcançável com o teclado. O valor correto é 0; Os valores positivos alteram a ordem de tabulação de toda a página e devem ser evitados.
Como foi que uma div com role='button' respondeu a Enter e Espaço?
Você deve ouvir o evento keydown e executar a ação quando a tecla é Enter ou Espaço. No caso do Espacio, convém chamar preventDefault para evitar o deslocamento da página. Sem esses manipuladores, o botão recebe foco, mas não é ativado com o teclado.
Como é que um botão está ativo ou desativado?
Para um botão de alternância, use aria-pressed='true' ou 'false' dependendo do estado. Para um botão desativado, use aria-disabled='true', que indica o estado, mas não bloqueia a interação por si só: isso impede a ação no código. O atributo nativo desativado é preferível quando um <button> é usado.
É difícil usar role='button' em um link?
Sim, quando o link navega para outro URL. Sobrescreva o papel de um <a href> com role='button' rompe a semântica de navegação e confunda os leitores de tela, que anunciam 'botão' quando o usuário espera um link. Se o elemento navegar, você deve manter a rolagem do link.
O que as ferramentas detectaram erros com role='button'?
Ferramentas automáticas como axe, Lighthouse ou WAVE sinalizam violações como falta de foco em elementos com função interativa. No entanto, o comportamento do teclado não é válido nem a lógica de estado, portanto a verificação confiável combina a audição automática com a verificação manual usando NVDA, VoiceOver ou Narrator.
Cumprir WCAG sem tocar no código?
Superposição de IA que promete cumprimento WCAG em 48 horas