Programação Por Equipe DevBras

Capa do artigo: Formulário que a pessoa termina: rótulo em cima, erro do lado e botão que fala

Formulário que a pessoa termina: rótulo em cima, erro do lado e botão que fala

Corte campos sem uso, empilhe numa coluna, mostre o erro em texto junto do campo e faça o botão dizer o que acontece. Com HTML e script prontos para adaptar.

Um cadastro de 14 campos, dois lado a lado no celular, botão "Enviar" e uma faixa vermelha no topo dizendo "Corrija os erros abaixo". Era esse o formulário da Casa Ipê, uma loja fictícia de utilidades, e mais da metade de quem começava não terminava. A resposta curta: peça só o que você vai usar agora, empilhe os campos numa coluna, deixe o rótulo sempre visível acima do campo, escreva o erro em texto logo abaixo do campo que falhou e faça o botão dizer o efeito ("Criar conta", não "Enviar"). O resto é implementação.

A pessoa não desiste do produto. Desiste da tela. Ela veio comprar, se inscrever ou pedir orçamento, e cada campo sem motivo, cada erro que não explica nada, é mais uma razão para fechar a aba e "tentar depois". Quase ninguém tenta depois.

Por que um formulário cansa mais do que parece

O cansaço não vem só da quantidade de campos. Vem das pequenas decisões que cada campo exige: o que ele quer, em que formato, se é obrigatório, por que a loja precisa disso. Cada dúvida gasta atenção, e a atenção acaba antes do botão.

Três mecanismos aparecem em quase todo formulário que perde gente:

  • Rótulo que some. Quando a instrução mora no placeholder, ela desaparece no primeiro caractere. Quem volta para revisar não sabe mais o que cada campo pedia.
  • Erro longe do campo. Uma mensagem genérica no topo obriga a pessoa a caçar o problema. No celular, o topo nem está na tela quando ela aperta o botão.
  • Silêncio depois do clique. Se nada muda enquanto a requisição viaja, a pessoa clica de novo. Em cadastro, isso vira conta duplicada. Em pedido, cobrança duplicada.

Um kit visual como o Bootstrap resolve grade, espaçamento e estilo dos campos. Ele não decide quais campos existem nem o que a mensagem de erro diz. Essa parte continua sendo sua.

Como enxugar e organizar o formulário, passo a passo

  1. Liste cada campo e onde o dado é usado. Na Casa Ipê, "data de nascimento", "como nos conheceu", "telefone fixo" e "confirme seu e-mail" não eram usados em lugar nenhum no primeiro pedido. Saíram. Sobraram nome, e-mail, senha, CEP, número, complemento e celular. Se um campo não tem destino, ele também é dado pessoal guardado sem motivo, como explica o post sobre campo com finalidade.
  2. Adie o que pode esperar. CPF só é necessário para a nota fiscal, então pode ser pedido no checkout. Preferências de comunicação cabem na página da conta.
  3. Empilhe numa coluna. Um campo por linha, na ordem em que a pessoa pensa: quem é, como falar com ela, onde entregar. Lado a lado só para pares que se leem juntos, como cidade e UF, e só em tela larga.
  4. Rótulo acima, sempre visível. Use <label for> ligado ao campo. Instrução de formato, como "8 dígitos", vai num texto de ajuda abaixo do rótulo. O motivo está detalhado em placeholder não substitui o rótulo.
  5. Use o tipo certo de campo. type="email", inputmode="numeric" e autocomplete trazem o teclado adequado e o preenchimento automático do navegador. O guia de inputs HTML5 que ajudam passa por cada um.
  6. Erro em texto, embaixo do campo, dizendo como corrigir. "Informe um e-mail com @ e domínio, como ana@exemplo.com" ensina. "Campo inválido" só acusa.
  7. Botão com o efeito e com estado de envio. "Criar conta". Durante a requisição, desabilite e troque para "Criando conta…". Se falhar, devolva o botão e explique. O post sobre o botão que mostra que espera aprofunda esse estado.

O HTML de um campo bem resolvido

Este é o campo de e-mail da Casa Ipê depois da revisão. Repare em três ligações: o rótulo aponta para o campo com for, o campo aponta para a ajuda e para o erro com aria-describedby, e o elemento de erro existe desde o início, vazio até ser preenchido. Assim o leitor de tela anuncia a ajuda quando o campo recebe foco e anuncia o erro quando ele aparece.

<form id="cadastro" action="/conta" method="post" novalidate>
  <div class="campo">
    <label for="email">E-mail</label>
    <p id="email-ajuda" class="ajuda">Vamos mandar a confirmação do pedido para ele.</p>
    <input id="email" name="email" type="email" autocomplete="email"
           required aria-describedby="email-ajuda email-erro">
    <p id="email-erro" class="erro" aria-live="polite"></p>
  </div>

  <button type="submit">Criar conta</button>
</form>

O novalidate desliga os balões nativos do navegador, que aparecem um de cada vez e com texto que você não controla. Os atributos required e type="email" continuam úteis, porque a API de validação do navegador ainda os lê. O script abaixo usa essa API, escreve a mensagem embaixo do campo e cuida do botão.

const form = document.getElementById('cadastro');
const email = form.elements.email;
const erroEmail = document.getElementById('email-erro');
const botao = form.querySelector('button[type="submit"]');

function validarEmail() {
  let mensagem = '';
  if (email.validity.valueMissing) {
    mensagem = 'Preencha o e-mail para receber a confirmação do pedido.';
  } else if (email.validity.typeMismatch) {
    mensagem = 'Informe um e-mail com @ e domínio, como ana@exemplo.com.';
  }
  erroEmail.textContent = mensagem;
  email.setAttribute('aria-invalid', mensagem ? 'true' : 'false');
  return mensagem === '';
}

email.addEventListener('blur', validarEmail);

form.addEventListener('submit', async (evento) => {
  evento.preventDefault();
  if (!validarEmail()) {
    email.focus();
    return;
  }
  botao.disabled = true;
  botao.textContent = 'Criando conta…';
  try {
    const resposta = await fetch(form.action, { method: 'POST', body: new FormData(form) });
    if (!resposta.ok) throw new Error('HTTP ' + resposta.status);
    window.location.href = '/conta/bem-vindo';
  } catch {
    botao.disabled = false;
    botao.textContent = 'Criar conta';
    erroEmail.textContent = 'Não conseguimos criar a conta agora. Seus dados continuam aqui; tente de novo em instantes.';
  }
});

Dois detalhes fazem diferença. A validação roda no blur, quando a pessoa sai do campo, e não a cada tecla: ninguém quer ver "e-mail inválido" enquanto ainda está digitando o "@". E, quando o envio falha, os dados continuam no formulário. Apagar tudo depois de um erro de rede é a forma mais rápida de perder um cliente.

Mensagens de erro que ensinam em vez de acusar

Uma boa mensagem responde a duas perguntas: o que está errado e o que fazer agora. Compare os pares que a Casa Ipê trocou:

  • "CEP inválido" virou "O CEP tem 8 números. Confira se não faltou nenhum."
  • "Senha fraca" virou "Use pelo menos 10 caracteres. Uma frase curta funciona bem."
  • "Erro no servidor" virou "Não conseguimos salvar agora. Seus dados continuam aqui; tente de novo em instantes."

Em formulários longos, além da mensagem embaixo de cada campo, vale um resumo no topo com links para os campos com problema, mostrado só depois da tentativa de envio. O resumo ajuda quem chegou ao fim e não vê o erro; a mensagem no campo ajuda quem está corrigindo. Um não substitui o outro.

O servidor valida de novo, sempre. O script do navegador é conforto, não proteção: qualquer pessoa pode enviar a requisição sem passar por ele. O ideal é o servidor devolver os erros por campo, no mesmo formato que o script já sabe exibir, para que a mensagem apareça no mesmo lugar venha de onde vier.

Erros comuns

  • Usar o placeholder como rótulo. A instrução some ao digitar, e quem revisa o formulário não sabe o que cada campo pedia.
  • Mostrar o erro só com borda vermelha. Quem não distingue cor, ou usa leitor de tela, não recebe a informação, e ninguém sabe se faltou o arroba ou se o servidor recusou.
  • Validar a cada tecla. O aviso aparece antes de a pessoa terminar de digitar e transforma o formulário numa bronca contínua.
  • Botão "Enviar" sem estado de espera. A pessoa clica de novo, e o sistema cria duas contas ou dois pedidos.
  • Limpar o formulário depois de uma falha. Quem teve erro de rede precisa digitar tudo outra vez, e muitos simplesmente vão embora.
  • Manter campo "porque sempre teve". Cada campo sem uso aumenta o abandono e ainda guarda dado pessoal sem finalidade.

Checklist

  • Cada campo tem um uso documentado no fluxo atual.
  • No celular, os campos estão numa única coluna.
  • Todo campo tem label visível ligado por for.
  • Campos de e-mail, telefone e CEP usam type, inputmode e autocomplete adequados.
  • O erro aparece em texto abaixo do campo e diz como corrigir.
  • O botão descreve a ação e fica desabilitado só enquanto a requisição está em andamento.
  • Uma falha de rede mantém os dados digitados.
  • O servidor repete a validação e devolve os erros por campo.

Abra o formulário mais importante do seu sistema no celular, preencha o e-mail errado de propósito e aperte o botão. A mensagem apareceu embaixo do campo, dizendo o que fazer, ou você teve que rolar a tela para descobrir o que deu errado?

Avalie este artigo

Referência: https://www.caelum.com.br/apostila-html-css-javascript/bootstrap-e-formularios-html5/