Formulários acessíveis: além do aria-label, o que realmente importa
1. A base semântica do HTML para formulários acessíveis
A acessibilidade em formulários começa muito antes de qualquer atributo ARIA. A base está no HTML semântico correto, que muitas vezes é negligenciado em favor de soluções mais "modernas" como aria-label.
O elemento <label> com o atributo for continua sendo a maneira mais robusta de associar um rótulo a um campo. Diferente de aria-label, que substitui o texto visível, o <label> mantém a relação explícita entre o texto e o input, beneficiando usuários de leitores de tela e também aqueles que usam interfaces de voz.
<!-- Correto: label com for -->
<label for="nome">Nome completo</label>
<input type="text" id="nome" name="nome">
<!-- Evitar: aria-label sem label visível -->
<input type="text" id="nome" name="nome" aria-label="Nome completo">
Para agrupamento lógico, <fieldset> e <legend> são indispensáveis. Eles informam ao leitor de tela que um conjunto de campos pertence a uma mesma categoria, como dados de endereço ou preferências de contato.
<fieldset>
<legend>Informações de contato</legend>
<label for="email">E-mail</label>
<input type="email" id="email" name="email">
<label for="tel">Telefone</label>
<input type="tel" id="tel" name="tel">
</fieldset>
A escolha do tipo de input também impacta a acessibilidade. type="email" ativa teclados específicos em dispositivos móveis e validação nativa no navegador. type="tel" exibe um teclado numérico em smartphones. type="number" oferece controles de incremento/decremento que funcionam por teclado.
2. Gerenciamento de estado e feedback em tempo real
Usuários de tecnologias assistivas precisam saber imediatamente quando um campo é inválido e qual o erro. Depender apenas de bordas vermelhas ou ícones visuais é insuficiente.
aria-describedby associa uma mensagem de erro ao campo, enquanto aria-invalid sinaliza o estado de erro para leitores de tela.
<label for="senha">Senha</label>
<input type="password" id="senha" name="senha"
aria-describedby="erro-senha"
aria-invalid="true">
<span id="erro-senha" role="alert">A senha deve ter no mínimo 8 caracteres.</span>
Para feedback dinâmico sem interromper o fluxo, aria-live é essencial. aria-live="polite" espera o usuário terminar a ação atual para anunciar a mensagem, enquanto aria-live="assertive" interrompe imediatamente.
<div aria-live="polite" aria-atomic="true">
<span id="status-cadastro"></span>
</div>
3. Navegação por teclado e foco gerenciado
A ordem de tabulação deve seguir a ordem visual do formulário. Evite tabindex positivo, que pode criar sequências confusas. Use tabindex="0" para elementos naturalmente não focáveis e tabindex="-1" para focar programaticamente.
O foco visível é obrigatório. Nunca remova o outline sem fornecer uma alternativa clara com :focus-visible.
input:focus-visible {
outline: 3px solid #005fcc;
outline-offset: 2px;
}
Em modais de confirmação ou validação, evite armadilhas de foco. Quando um modal abre, o foco deve ir para o primeiro elemento interativo. Quando fecha, deve retornar ao elemento que o acionou.
// Exemplo conceitual de gerenciamento de foco
function abrirModal() {
const modal = document.getElementById('modal-confirmacao');
modal.style.display = 'block';
document.getElementById('btn-confirmar').focus();
}
function fecharModal() {
const modal = document.getElementById('modal-confirmacao');
modal.style.display = 'none';
document.getElementById('btn-abrir-modal').focus();
}
O uso de accesskey deve ser cauteloso. Pode conflitar com atalhos do navegador ou de leitores de tela. Prefira fornecer atalhos de teclado documentados e opcionais.
4. Validação nativa vs. validação customizada
A validação HTML5 nativa (required, pattern, minlength, maxlength) já oferece suporte básico a leitores de tela, mas as mensagens padrão variam entre navegadores e nem sempre são claras.
A Constraint Validation API permite personalizar mensagens sem perder a acessibilidade.
const campoEmail = document.getElementById('email');
campoEmail.addEventListener('invalid', function(event) {
event.preventDefault();
if (this.validity.valueMissing) {
this.setCustomValidity('O campo de e-mail é obrigatório.');
} else if (this.validity.typeMismatch) {
this.setCustomValidity('Insira um e-mail válido, como exemplo@dominio.com.');
}
this.reportValidity();
});
Evite alert() para erros de validação. Prefira feedback inline com aria-errormessage, que substitui aria-describedby quando o campo está em estado de erro.
<label for="cpf">CPF</label>
<input type="text" id="cpf" name="cpf"
aria-errormessage="erro-cpf"
aria-invalid="true">
<span id="erro-cpf" role="alert">CPF inválido. Formato esperado: 000.000.000-00.</span>
5. Suporte a tecnologias assistivas além do leitor de tela
Acessibilidade não se resume a leitores de tela. Usuários com baixa visão precisam de contraste adequado (pelo menos 4.5:1 para texto normal) e tamanho de fonte ajustável sem quebra do layout.
Para mobilidade reduzida, alvos de toque devem ter no mínimo 44x44 pixels (recomendação WCAG 2.2). Botões e campos muito próximos podem causar erros de clique.
button, input[type="submit"], input[type="reset"] {
min-height: 44px;
min-width: 44px;
padding: 12px 16px;
}
O atributo autocomplete melhora significativamente a experiência para usuários com deficiências cognitivas e motoras, permitindo preenchimento automático.
<input type="text" id="endereco" name="endereco" autocomplete="street-address">
<input type="text" id="cidade" name="cidade" autocomplete="address-level2">
<input type="text" id="cep" name="cep" autocomplete="postal-code">
6. Internacionalização e localização em formulários acessíveis
Placeholder nunca substitui label. Placeholder desaparece ao digitar, não é acessível por padrão em todos os leitores de tela e tem baixo contraste.
<!-- ERRADO: placeholder como único rótulo -->
<input type="text" placeholder="Digite seu nome">
<!-- CORRETO: label visível -->
<label for="nome">Nome completo</label>
<input type="text" id="nome" placeholder="Ex: Maria Silva">
Para formatação de dados, use inputmode para ativar o teclado correto em dispositivos móveis sem alterar o tipo do input.
<input type="text" id="moeda" inputmode="decimal" pattern="[0-9]+([.,][0-9]{1,2})?"
lang="pt-BR" aria-label="Valor em reais">
Em formulários multilíngues, use dir="rtl" para idiomas da direita para a esquerda e defina lang no elemento <html> ou em partes específicas do formulário.
<div lang="ar" dir="rtl">
<label for="nome-ar">الاسم الكامل</label>
<input type="text" id="nome-ar">
</div>
7. Testes práticos de acessibilidade em formulários
Ferramentas automatizadas como axe DevTools e Lighthouse capturam problemas básicos, mas não detectam tudo. Um formulário pode passar em todos os testes automatizados e ainda ser inacessível.
Testes manuais são indispensáveis:
- Navegue por todo o formulário usando apenas a tecla Tab.
- Verifique se o foco é visível em todos os elementos interativos.
- Teste com leitor de tela (NVDA no Windows, VoiceOver no Mac, TalkBack no Android).
- Confirme que mensagens de erro são anunciadas automaticamente.
- Verifique a ordem de tabulação com o formulário em diferentes tamanhos de tela.
Checklist de auditoria para formulários:
- [ ] Todos os campos têm
<label>visível e acessível - [ ] Mensagens de erro usam
aria-describedbyouaria-errormessage - [ ] Foco visível em todos os elementos interativos
- [ ] Ordem de tabulação segue a ordem visual
- [ ] Contraste de texto e ícones atende WCAG AA
- [ ] Alvos de toque têm no mínimo 44x44 pixels
- [ ]
autocompleteconfigurado para campos comuns - [ ] Formulário funcional apenas com teclado
Referências
- W3C Web Accessibility Initiative - Forms Tutorial — Guia oficial da WAI sobre formulários acessíveis, incluindo labels, agrupamento e validação.
- MDN Web Docs - ARIA: form role — Documentação técnica sobre o papel ARIA de formulários e boas práticas de uso.
- Deque University - Accessible Forms Checklist — Checklist prático para auditoria de formulários acessíveis, com exemplos de código.
- WebAIM - Creating Accessible Forms — Artigo detalhado sobre técnicas de acessibilidade em formulários, incluindo validação e feedback.
- Smashing Magazine - An Extensive Guide To Web Form Accessibility — Guia extenso com exemplos práticos de formulários acessíveis e armadilhas comuns.
- W3C - Using the aria-errormessage attribute — Técnica oficial para usar
aria-errormessageem validação de formulários. - A11y Project - Accessible Forms — Coletânea de boas práticas e padrões para formulários acessíveis.