Formulários acessíveis: rótulos, erros e teclado
Rótulos associados, erros descritos em texto, teclado, foco visível e autocomplete: o que a WCAG 2.2 pede de um formulário, com exemplos em HTML.
Nesta página 11 min de leitura
Um formulário acessível tem, em cada campo, um rótulo visível ligado ao campo no código e que diz para que ele serve. Ele avisa os erros em texto, aponta o campo errado e sugere a correção quando ela é conhecida. Funciona inteiro pelo teclado, com foco sempre visível. Nos campos com dados da própria pessoa, declara o propósito com autocomplete. E, desde a WCAG 2.2, não pede de novo o que a pessoa já informou no mesmo processo nem trava o login para quem usa gerenciador de senhas.
O guia segue a WCAG 2.2 (edição de dezembro de 2024), nível AA, e os tutoriais de formulários do W3C. Os exemplos são HTML puro; em React, Vue ou outro framework, o HTML final precisa ter a mesma estrutura.
Os critérios que se aplicam
| Critério | Nível | O que pede no formulário |
|---|---|---|
| 1.3.1 Informações e relações | A | Rótulo associado ao campo e grupos de campos marcados no código |
| 1.3.5 Identificar o propósito de entrada | AA | Campos com dados do usuário têm o propósito declarado no código |
| 2.1.1 Teclado | A | Tudo funciona pelo teclado |
| 2.4.6 Cabeçalhos e rótulos | AA | Rótulos descrevem o propósito do campo |
| 2.4.7 Foco visível | AA | O indicador de foco do teclado aparece |
| 3.3.1 Identificação de erro | A | O campo com erro é identificado e o erro é descrito em texto |
| 3.3.2 Rótulos ou instruções | A | Há rótulos ou instruções quando o conteúdo pede entrada de dados |
| 3.3.3 Sugestão de erro | AA | Quando a correção é conhecida, ela é sugerida, salvo se isso comprometer a segurança |
| 3.3.4 Prevenção de erro (legal, financeiro, dados) | AA | Envios com efeito legal ou financeiro podem ser revertidos, verificados ou confirmados |
| 3.3.7 Entrada redundante (novo na 2.2) | A | Não pedir de novo o que já foi informado no mesmo processo |
| 3.3.8 Autenticação acessível, mínimo (novo na 2.2) | AA | Login sem teste de memória ou transcrição sem alternativa |
| 4.1.2 Nome, função, valor | A | Nome e tipo de cada controle, e seus estados, disponíveis para tecnologias assistivas |
Os nomes em português são traduções deste texto. A redação oficial de cada critério está na WCAG 2.2.
Rótulos
Associe o rótulo ao campo
O elemento label com o atributo for igual ao id do campo é a forma recomendada pelo tutorial de rótulos do W3C (Labeling Controls). Com isso, o leitor de tela anuncia o rótulo quando o campo recebe foco, e clicar no texto do rótulo leva ao campo, o que aumenta a área de clique. Quando o formulário coleta dados pessoais, o que acontece com eles precisa estar explicado na política de privacidade do site.
<label for="email">E-mail</label>
<input id="email" name="email" type="email" autocomplete="email">Também vale colocar o campo dentro do label (rótulo implícito), mas o W3C observa que o rótulo explícito tem suporte mais amplo.
Placeholder não é rótulo
A especificação do HTML diz que o atributo placeholder não deve ser usado como alternativa ao rótulo (HTML Living Standard). O texto some quando a pessoa começa a digitar, então quem se distrai ou tem dificuldade de memória perde a referência. Se usar placeholder como exemplo de formato, ele também precisa de contraste de 4,5:1, como explica o guia de contraste de cores.
<!-- Evite: o único rótulo some ao digitar -->
<input type="tel" placeholder="Telefone">
<!-- Prefira: rótulo visível e exemplo à parte -->
<label for="tel">Telefone com DDD</label>
<input id="tel" type="tel" autocomplete="tel" aria-describedby="tel-dica">
<p id="tel-dica">Exemplo: 11 91234-5678</p>O atributo aria-describedby liga o campo a um texto de apoio, que o leitor de tela anuncia depois do rótulo.
Rótulos que dizem para que o campo serve
O critério 2.4.6 pede que rótulos descrevam o propósito. "Nome" num formulário de presente pode ser o nome de quem compra ou de quem recebe; "Nome de quem vai receber" resolve. O formato esperado também entra aqui: se a data é DD/MM/AAAA, diga no rótulo ou na dica.
Agrupe campos relacionados
Botões de opção (radio) e grupos de caixas de seleção precisam de um título para o grupo. O W3C recomenda fieldset com legend e pede uma legenda curta, porque alguns leitores de tela a repetem a cada campo (Grouping Controls).
<fieldset>
<legend>Forma de entrega</legend>
<input type="radio" id="entrega-normal" name="entrega" value="normal">
<label for="entrega-normal">Normal (até 7 dias úteis)</label>
<input type="radio" id="entrega-expressa" name="entrega" value="expressa">
<label for="entrega-expressa">Expressa (até 2 dias úteis)</label>
</fieldset>Campos obrigatórios
Indique o obrigatório em texto, no próprio rótulo, e não só com cor ou um asterisco sem explicação. O atributo required informa o estado às tecnologias assistivas e ativa a validação do navegador.
<label for="nome">Nome completo (obrigatório)</label>
<input id="nome" name="nome" autocomplete="name" required>Rótulo escondido e aria-label
Um campo de busca com ícone de lupa pode não ter rótulo visível, desde que o propósito fique claro pelo contexto. O W3C admite esconder o rótulo visualmente, mas avisa que display: none e visibility: hidden também o escondem dos leitores de tela. Os atributos aria-label e aria-labelledby dão nome ao campo sem texto visível e, segundo o tutorial, só devem ser usados quando o rótulo é claro pelo conteúdo em volta.
Botões e componentes próprios
O critério 4.1.2 pede que nome, função e estado de cada controle estejam disponíveis para tecnologias assistivas. Elementos nativos (button, input, select, textarea) já trazem isso. Um button recebe o nome do próprio texto.
<!-- Evite: não recebe foco nem é anunciado como botão -->
<div class="btn" onclick="enviar()">Enviar</div>
<!-- Prefira -->
<button type="submit">Enviar pedido</button>A NBR 17225, no anexo A (A.1.6), lembra que componentes customizados, como modais, pop-ups e carrosséis, não têm semântica e comportamento definidos pelo navegador, e que essa responsabilidade passa para quem desenvolve. Seletores de data, listas suspensas com busca e campos de upload "estilizados" são os que mais exigem cuidado em formulários.
Erros: identificar, descrever e sugerir
Três critérios tratam de erro. O 3.3.1 pede que, quando o erro é detectado automaticamente, o campo seja identificado e o erro descrito em texto. Borda vermelha sozinha não basta. O 3.3.3 pede a sugestão de correção quando ela é conhecida, salvo se isso comprometer a segurança ou o propósito do conteúdo. O 3.3.4 vale para formulários com efeito legal ou financeiro, que alteram ou apagam dados do usuário, ou que enviam respostas de prova: o envio precisa ser reversível, verificado com chance de correção ou confirmado numa etapa de revisão (WCAG 2.2, 3.3.4).
O tutorial de notificações do W3C (User Notifications) recomenda:
listar os erros no topo do formulário, sob um título claro;
dar também a mensagem junto de cada campo;
ligar cada campo à sua mensagem com
aria-describedby;levar o foco ao primeiro campo com erro;
indicar o erro também no título da página, que o leitor de tela anuncia ao carregar;
confirmar o sucesso do envio, e não só os erros.
O atributo aria-invalid="true" marca o campo com erro para as tecnologias assistivas; é a técnica ARIA21 do W3C para o critério 3.3.1 (ARIA21).
<!-- Resumo no topo, depois do envio -->
<div id="erros" tabindex="-1">
<h2>O formulário tem 2 erros</h2>
<ul>
<li><a href="#cep">CEP: use 8 dígitos</a></li>
<li><a href="#email">E-mail: falta o @</a></li>
</ul>
</div>
<!-- Campo com erro -->
<label for="cep">CEP (obrigatório)</label>
<input id="cep" name="cep" autocomplete="postal-code" inputmode="numeric"
aria-invalid="true" aria-describedby="cep-erro">
<p id="cep-erro">Erro: o CEP precisa ter 8 dígitos. Exemplo: 01310-100.</p>Depois de um envio com erro, mantenha o que a pessoa digitou. Apagar o formulário obriga a digitar tudo de novo e, num processo de várias etapas, pode falhar no critério 3.3.7, tratado mais abaixo.
Teclado e foco visível
O critério 2.1.1 pede que toda função funcione pelo teclado. Em formulário, isso inclui chegar a cada campo com Tab, marcar opções com espaço e setas, abrir e escolher em listas, usar o seletor de data e enviar com Enter ou com o botão. Componentes nativos já fazem isso; os customizados precisam ser programados para fazer.
O critério 2.4.7 pede que o foco do teclado fique visível. O erro mais comum é remover o contorno padrão com outline: none sem pôr outro no lugar. Se trocar o estilo, o novo indicador precisa de contraste de 3:1 com o fundo (critério 1.4.11), e a NBR 17225 traz esse contraste como requisito (item 5.11.6).
/* Indicador próprio: #1a5fb4 sobre branco tem 6,3:1 */
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible {
outline: 3px solid #1a5fb4;
outline-offset: 2px;
}Na WCAG 2.2, o critério 2.4.11 pede ainda que o campo em foco não fique totalmente escondido por cabeçalho fixo, banner de cookies ou chat. Os detalhes estão no guia WCAG 2.2 nível AA.
Autocomplete e o propósito do campo (1.3.5)
O critério 1.3.5 pede que campos que coletam dados sobre o próprio usuário tenham o propósito identificável pelo código. A lista de propósitos está na seção 7 da WCAG e segue os valores de preenchimento automático do HTML: name, given-name, family-name, email, tel, street-address, postal-code, bday, username, new-password, current-password, entre outros (WCAG 2.2, seção 7).
Segundo o Understanding 1.3.5:
O critério vale só para dados sobre o usuário. O campo "e-mail do amigo" num formulário de indicação não entra.
O que conta é o propósito estar no código. Se o navegador preenche ou não, é irrelevante para a avaliação, e o preenchimento por adivinhação do navegador não basta.
Os prefixos
shippingebillingseparam endereço de entrega e de cobrança.O ganho é maior para pessoas com deficiências de linguagem e memória, que não precisam lembrar e digitar os dados.
<label for="nome-entrega">Nome de quem vai receber</label>
<input id="nome-entrega" autocomplete="shipping name">
<label for="cep-entrega">CEP de entrega</label>
<input id="cep-entrega" autocomplete="shipping postal-code" inputmode="numeric">
<label for="nascimento">Data de nascimento</label>
<input id="nascimento" type="date" autocomplete="bday">Critérios novos da WCAG 2.2 que afetam formulários
3.3.7 Entrada redundante
Num mesmo processo, o que a pessoa já informou não pode ser pedido de novo, a menos que venha preenchido ou disponível para seleção. As exceções são: digitar de novo é essencial, o dado é exigido por segurança ou o dado anterior deixou de valer (WCAG 2.2, 3.3.7). O preenchimento automático do navegador não conta como solução, segundo o Understanding 3.3.7; o próprio site precisa oferecer o dado. Pedir para confirmar uma senha nova que não aparece na tela é permitido.
<input type="checkbox" id="mesmo-endereco" checked>
<label for="mesmo-endereco">Endereço de cobrança igual ao de entrega</label>3.3.8 Autenticação acessível (mínimo)
Nenhuma etapa do login pode exigir teste de função cognitiva, como lembrar uma senha, transcrever caracteres ou resolver quebra-cabeça, sem uma alternativa ou um mecanismo de ajuda (WCAG 2.2, 3.3.8). A própria WCAG cita como mecanismos aceitos o preenchimento por gerenciadores de senha e o copiar e colar. Na prática, segundo o Understanding 3.3.8:
Bloquear o colar no campo de senha ou no código de verificação é falha.
Bloquear o preenchimento automático, por exemplo com script, é falha se não houver alternativa.
CAPTCHA de digitar caracteres distorcidos falha sem alternativa; CAPTCHA de reconhecer objetos é aceito no nível AA.
Link de acesso por e-mail (técnica G218) e login com provedor externo via OAuth são formas de cumprir.
<label for="usuario">E-mail</label>
<input id="usuario" type="email" autocomplete="username">
<label for="senha">Senha</label>
<input id="senha" type="password" autocomplete="current-password">
<label for="codigo">Código de verificação</label>
<input id="codigo" inputmode="numeric" autocomplete="one-time-code">
<!-- Evite: impede o gerenciador de senhas e o colar -->
<input type="password" autocomplete="off" onpaste="return false">O valor one-time-code faz parte da lista de preenchimento automático da especificação do HTML (HTML Living Standard, Autofill), embora não esteja na lista da seção 7 da WCAG.
2.5.8 Tamanho do alvo
Caixas de seleção, botões de opção e ícones de mostrar senha ou limpar campo são alvos pequenos. A WCAG 2.2 pede pelo menos 24 por 24 pixels CSS ou espaçamento suficiente. Controles nativos com o tamanho padrão do navegador, sem alteração do site, estão na exceção (WCAG 2.2, 2.5.8). Se o site redesenhou esses controles e eles ficaram com menos de 24 pixels, meça o espaçamento em volta de cada um.
Como testar um formulário
Preencha e envie o formulário só com o teclado. Anote todo campo ou controle que não recebe foco, que prende o foco ou cujo foco some.
Confira o nome de cada campo. No Chrome, a aba Accessibility do DevTools mostra a árvore de acessibilidade e as propriedades calculadas do elemento. Com um leitor de tela (NVDA no Windows, VoiceOver no Mac e no iPhone, TalkBack no Android), ouça o que é anunciado em cada campo.
Envie vazio e depois com dados inválidos. Veja se cada erro aparece em texto, aponta o campo, sugere a correção e se o foco vai para o erro ou para o resumo.
Confira se o que foi digitado continua lá depois do erro.
Inspecione os atributos
autocompletedos campos com dados pessoais.Teste o login com um gerenciador de senhas e tente colar a senha e o código.
Percorra fluxos de várias etapas e anote dados pedidos duas vezes.
Meça alvos pequenos e confira o contraste de bordas, placeholder e indicador de foco.
Ferramentas automáticas acham campos sem rótulo e atributos faltando, mas o W3C avisa que elas não determinam sozinhas se um site é acessível (Selecting Web Accessibility Evaluation Tools). Clareza das mensagens, ordem do foco e fluxos de várias etapas pedem teste humano.
Formulários na NBR 17225
A ABNT NBR 17225:2025 reúne os itens de formulário na seção 5.9, "Formulários e entrada de dados" (ABNT NBR 17225:2025). Alguns requisitos e o critério WCAG a que a norma os associa:
| Item da NBR (requisito) | Critério WCAG citado na norma |
|---|---|
| 5.9.1 Rótulo de campo | 3.3.2 e 4.1.2 |
| 5.9.3 Rótulo de campo associado | 1.3.1 |
| 5.9.4 Rótulo de campo descritivo | 2.4.6 |
| 5.9.7 Campos obrigatórios | 3.3.2 |
| 5.9.8 Tipo de dado determinado | 1.3.5 |
| 5.9.9 Mensagem de erro descritiva | 3.3.1 |
| 5.9.10 Sugestão de correção | 3.3.3 |
| 5.9.12 Prevenção de erro para formulários críticos | 3.3.4 |
| 5.9.15 Reentrada de dados | 3.3.7 |
| 5.9.18 Autenticação acessível (mínima) | 3.3.8 |
A norma também lista o CAPTCHA entre os itens críticos do anexo A. Quem está obrigado pela Lei Brasileira de Inclusão e como a norma entra nisso está no guia LBI e NBR 17225: o que a lei exige de um site. Este texto explica a norma técnica; não é parecer jurídico.
Como verificar o seu site
A checagem grátis do WebVyze analisa a página inicial, sem cadastro, e aponta riscos de acessibilidade ligados à lei. Formulários costumam ficar em outras páginas (contato, cadastro, checkout); o plano grátis audita até 5 páginas de um site a cada 30 dias. Os testes manuais desta lista, como teclado, leitor de tela e fluxos de várias etapas, continuam necessários. O mesmo vale para widgets de acessibilidade instalados por cima do site, discutidos em overlay de acessibilidade.
Perguntas frequentes
- Posso esconder o rótulo e deixar só o ícone, como numa busca com lupa?
- Pode, desde que o propósito do campo seja claro pelo contexto e o campo tenha um nome acessível, por exemplo com um rótulo visualmente oculto ou aria-label. O W3C avisa que display: none e visibility: hidden também escondem o rótulo dos leitores de tela, então a técnica de ocultar precisa manter o texto no código.
- Validar enquanto a pessoa digita é proibido?
- A WCAG não proíbe. Os critérios pedem que o erro seja identificado e descrito em texto, com sugestão quando ela é conhecida. Mensagens que aparecem a cada tecla, antes de a pessoa terminar de digitar, costumam atrapalhar; validar ao sair do campo ou ao enviar é uma escolha mais calma.
- A ordem dos campos importa?
- Sim. A ordem do foco precisa preservar o sentido e a operação (critério 2.4.3), e a ordem de leitura precisa ser determinável pelo código (1.3.2). Na prática, a ordem do HTML deve seguir a ordem visual.
- Botão de enviar desabilitado até preencher tudo é um problema?
- O contraste do botão desabilitado está isento, porque componentes inativos não têm exigência de contraste. O problema costuma ser outro: a pessoa não sabe o que falta. Deixar o botão ativo e mostrar os erros ao enviar dá a informação que ela precisa.
Veja o que o seu site precisa corrigir.
Checagem grátis por lei, com a causa e o guia de correção de cada problema.
Continue lendo
- SEO técnico
Robôs de IA no robots.txt: busca, acesso do usuário e treinamento
GPTBot, ClaudeBot, OAI-SearchBot, Google-Extended: o que cada robô de IA faz, se respeita o robots.txt e como bloquear o treinamento sem sair da busca.
- SEO técnico
Redirecionamentos: cadeias, loops e como corrigir
Como o Google trata 301, 302, 307 e 308, o que cadeias e loops causam no rastreamento e na velocidade, e como mapear, corrigir e testar redirecionamentos.
- SEO técnico
llms.txt: o que é, o que não faz e como criar
O llms.txt resume o site para agentes de IA. Veja o formato, o que Google e outras empresas dizem sobre ele, quando vale criar e como escrever um bom arquivo.