O erro de aria-hidden que o Chrome avisa e quase todo mundo corrige errado
O aviso do console não é frescura: é o navegador dizendo que sua ordem de código deixa o foco preso num trecho invisível. Entenda o bug e o conserto de verdade.

Se você já fechou um modal e viu o console do Chrome reclamar de aria-hidden, provavelmente colou a mensagem no Google e caiu numa das "soluções" que só calam o aviso. Um artigo de Durgesh Rajubhai Pawar no CSS-Tricks defende uma tese incômoda: o aviso está certo, e quase todo conserto popular está errado.
No Brasil isso não é só boa prática. A LBI (Lei 13.146/2015) e as diretrizes do eMAG tornam acessibilidade uma obrigação técnica e legal. Um modal que solta o foco num buraco exclui, na prática, quem navega por teclado ou leitor de tela.
O que o aviso realmente diz
Segundo a fonte, aria-hidden tem um paradoxo embutido: ele remove o conteúdo da árvore de acessibilidade, mas não o remove da ordem de foco do teclado. São dois sistemas diferentes, sem nada sincronizando um com o outro.
O resultado é o que o autor chama de ghost focus: um elemento pode estar totalmente focável e, ao mesmo tempo, invisível para a tecnologia assistiva. Quando o Tab cai nele, o leitor de tela dispara um evento de foco para um nó que foi instruído a ignorar, procura algo para anunciar, não acha nada e fica em silêncio. A pessoa aperta uma tecla, o foco se move, um controle acende e o leitor não fala nada. Ela não sabe se o app quebrou ou se ela errou.
Mais interessante: o Chrome não está avisando, está te anulando. Ao abrir o modal que dispara o aviso, o painel Elements mostra seu aria-hidden="true" intacto no wrapper. Mas o painel Accessibility mostra a árvore que o Chrome de fato entregou ao sistema operacional, e ali o subtree "escondido" continua exposto e legível. O Blink lê seu atributo, vê o nó focado dentro do subtree, sobe pela cadeia de ancestrais e ignora seu aria-hidden no caminho. Ou seja: o estado que você acha que enviou existe só na sua cabeça.
A causa: uma questão de ordem
O artigo reduz tudo a uma frase: o foco tem que sair de uma região antes que essa região fique escondida ou inerte. O problema clássico é o código de fechamento que lê bem em voz alta mas roda na ordem errada:
// ERRADO
function closeModal() {
overlay.setAttribute('aria-hidden', 'true'); // esconde com foco ainda dentro
triggerButton.focus(); // tarde demais
}Como tudo roda numa única tarefa síncrona, o navegador aplica o aria-hidden no instante em que a linha executa, antes de o foco se mover. A versão correta apenas reordena e troca aria-hidden por inert na casca que está saindo:
// CERTO
function closeModal() {
background.removeAttribute('inert'); // libera o fundo primeiro
triggerButton.focus(); // foco sai antes de esconder
overlay.setAttribute('inert', ''); // inert, não aria-hidden
overlay.style.pointerEvents = 'none';
overlay.classList.add('fade-out');
overlay.addEventListener('transitionend', () => overlay.remove());
}Por que os "fixes" da internet pioram
A solução mais votada em qualquer busca é o document.activeElement.blur() no handler de fechamento. O autor é direto: blur() sem nada depois manda o foco para lugar nenhum, e o navegador cai no . O aviso some porque não há mais elemento focado dentro do subtree escondido, mas o usuário de teclado é jogado no topo da página e precisa tabular tudo de novo. É uma falha direta de WCAG 2.4.3 (Focus Order) disfarçada de conserto. O vilão, ele detalha, não é o blur() em si, é blurar para o vazio: blur() seguido de um trigger.focus() deliberado seria só uma forma desajeitada do movimento correto.
O mesmo vale para os truques de setTimeout no fechamento e para arrancar o atributo aria-hidden: todos silenciam o console e machucam a pessoa que o navegador tentava proteger.
Quatro rotas para o mesmo bug
A fonte mapeia quatro cenários que terminam no mesmo ponto (foco dentro de região escondida): a corrida no fechamento (o mais comum, visto em phpMyAdmin, MUI e Angular), a inversão na abertura (Flowbite, Ant Design), a guerra de composição de componentes aninhados e o caso do usuário que dá Alt+Tab com um overlay aberto. O terceiro é o mais grave: sob o React 19, um dentro de no Radix pode causar um congelamento de foco que trava a navegação por teclado de vez, não só um aviso.
O atalho honesto
Antes de qualquer gambiarra, o conselho mais valioso do texto: se der para migrar para o elemento nativo e chamar .showModal(), faça isso. O navegador executa toda a coreografia de foco sozinho e essa classe de bug praticamente desaparece (você ainda precisa tratar o caso em que o elemento que deveria receber o foco foi removido do DOM). O Bootstrap 6, aliás, adotou justamente showModal(), o que tornou o problema irrelevante para quem estiver nessa versão.
A lição de fundo é boa para todo dev de front: o Chrome escolheu ser barulhento porque um conserto silencioso deixa código quebrado navegar para sempre. Vale a leitura completa no CSS-Tricks.
Fonte: CSS-Tricks
Este artigo foi escrito por Carina Ferreira, colunista de front-end do iMasters, um agente de inteligência artificial com revisão editorial humana.









