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.

Checar meu site grátisVer os planos
Nesta página 11 min de leitura
  1. Os critérios que se aplicam
  2. Rótulos
  3. Botões e componentes próprios
  4. Erros: identificar, descrever e sugerir
  5. Teclado e foco visível
  6. Autocomplete e o propósito do campo (1.3.5)
  7. Critérios novos da WCAG 2.2 que afetam formulários
  8. Como testar um formulário
  9. Formulários na NBR 17225
  10. Como verificar o seu site

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érioNívelO que pede no formulário
1.3.1 Informações e relaçõesARótulo associado ao campo e grupos de campos marcados no código
1.3.5 Identificar o propósito de entradaAACampos com dados do usuário têm o propósito declarado no código
2.1.1 TecladoATudo funciona pelo teclado
2.4.6 Cabeçalhos e rótulosAARótulos descrevem o propósito do campo
2.4.7 Foco visívelAAO indicador de foco do teclado aparece
3.3.1 Identificação de erroAO campo com erro é identificado e o erro é descrito em texto
3.3.2 Rótulos ou instruçõesAHá rótulos ou instruções quando o conteúdo pede entrada de dados
3.3.3 Sugestão de erroAAQuando a correção é conhecida, ela é sugerida, salvo se isso comprometer a segurança
3.3.4 Prevenção de erro (legal, financeiro, dados)AAEnvios com efeito legal ou financeiro podem ser revertidos, verificados ou confirmados
3.3.7 Entrada redundante (novo na 2.2)ANã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)AALogin sem teste de memória ou transcrição sem alternativa
4.1.2 Nome, função, valorANome 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 shipping e billing separam 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

  1. 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.

  2. 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.

  3. 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.

  4. Confira se o que foi digitado continua lá depois do erro.

  5. Inspecione os atributos autocomplete dos campos com dados pessoais.

  6. Teste o login com um gerenciador de senhas e tente colar a senha e o código.

  7. Percorra fluxos de várias etapas e anote dados pedidos duas vezes.

  8. 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 campo3.3.2 e 4.1.2
5.9.3 Rótulo de campo associado1.3.1
5.9.4 Rótulo de campo descritivo2.4.6
5.9.7 Campos obrigatórios3.3.2
5.9.8 Tipo de dado determinado1.3.5
5.9.9 Mensagem de erro descritiva3.3.1
5.9.10 Sugestão de correção3.3.3
5.9.12 Prevenção de erro para formulários críticos3.3.4
5.9.15 Reentrada de dados3.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.
Sobre o autor

Daniel Paz

Especialista em WordPress, performance e SEO, fundador da WebOption

Daniel Paz é especialista em WordPress, performance e SEO, fundador da WebOption e palestrante internacional. Com mais de 18 anos de experiência em desenvolvimento web, ajuda empresas a transformar sites em plataformas rápidas, eficientes e orientadas a resultados.

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.

Checar meu site grátisCriar conta grátis

Continue lendo

Parceiros

Benefícios de parceiros com o mesmo cupom.

WPLIGHT

Links de parceiros. Podemos receber uma comissão, sem custo adicional para você.