Sobre este problema HTML
O atributo role="button" informa tecnologias assistivas como leitores de ecrã que um elemento se comporta como um botão — um widget usado para executar ações como submeter um formulário, abrir um diálogo, ou desencadear um comando. Quando um elemento <button> aparece dentro de um elemento com role="button", o resultado é um controlo interativo aninhado. A especificação HTML proíbe explicitamente isto porque conteúdo interativo não deve ser aninhado dentro de outro conteúdo interativo.
Este aninhamento causa problemas reais. Os leitores de ecrã podem anunciar o elemento exterior como um botão mas falhar ao reconhecer ou alcançar o <button> interior. Os utilizadores de teclado podem não conseguir focar ou ativar o controlo interior. Diferentes navegadores lidam com a situação de forma inconsistente — alguns podem ignorar completamente um dos controlos, outros podem disparar eventos no elemento errado. O resultado final é uma interface que está quebrada para muitos utilizadores.
Este problema surge comummente em alguns cenários:
-
Um
<div>ou<span>receberole="button"e depois um<button>é colocado dentro dele para fins de estilo ou gestão de cliques. -
Uma biblioteca de componentes envolve conteúdo num contentor
role="button", e um programador adiciona um<button>dentro sem perceber o conflito. -
Um cartão personalizado ou item de lista é tornado clicável com
role="button", mas também contém botões de ação dentro dele.
A correção depende da sua intenção. Se o elemento exterior é o controlo interativo pretendido, remova o <button> interior e gira as interações no elemento exterior. Se o <button> interior é o controlo pretendido, remova role="button" do ancestral. Se ambos precisam de ser independentemente clicáveis, reestruture a marcação para que nenhum seja descendente do outro.
Exemplos
❌ Incorreto: <button> dentro de um elemento com role="button"
<div role="button" tabindex="0" onclick="handleClick()">
<button type="button">Click me</button>
</div>
Isto é inválido porque o <button> é um descendente do <div> que tem role="button".
✅ Opção de correção 1: Use apenas o elemento <button>
Se o <button> interior é o controlo real, remova role="button" do wrapper:
<div>
<button type="button" onclick="handleClick()">Click me</button>
</div>
✅ Opção de correção 2: Use apenas o elemento exterior role="button"
Se o elemento exterior é o controlo interativo pretendido, remova o <button> interior:
<div role="button" tabindex="0" onclick="handleClick()">
Click me
</div>
Note que ao usar role="button" num elemento que não é <button>, você também deve gerir eventos de teclado (Enter e Space) manualmente. Um <button> nativo fornece isto gratuitamente, portanto prefira a opção 1 quando possível.
❌ Incorreto: Cartão clicável contendo botões de ação
<div role="button" tabindex="0" class="card">
<h3>Item title</h3>
<p>Description text</p>
<button type="button">Delete</button>
</div>
✅ Correção: Separe o link do cartão dos botões de ação
<div class="card">
<h3><button type="button" class="card-link">Item title</button></h3>
<p>Description text</p>
<button type="button">Delete</button>
</div>
Nesta abordagem, a ação principal do cartão é gerida por um <button> no título, enquanto o botão “Delete” permanece um controlo independente. Nenhum está aninhado dentro do outro, e ambos são acessíveis para utilizadores de teclado e leitores de ecrã.
Encontre problemas como este automaticamente
O Rocket Validator analisa milhares de páginas em segundos, detetando problemas HTML em todo o seu site.
Saiba mais: