Como fazer um formulário em HTML
Um formulário é um elemento <form> com campos e um botão de envio. Cada campo precisa de um name: é a chave com que o valor é enviado. Preencha o formulário e aperte Send. A prévia não envia nada para lugar nenhum; ela mostra exatamente o que o navegador teria enviado.
As partes:
actioné a URL para onde os dados vão, emethodé como (postaqui).nameem todo campo. O valor é o que o usuário digitou.<label>dá nome a cada campo na tela e para os leitores de tela (veja label no HTML).requiredetype="email"fazem o navegador verificar os campos antes de enviar. Tente enviar com o nome vazio, ou comabcno e-mail.- O botão de envio envia o formulário. Apertar Enter num campo de texto também envia.
action e method: para onde e como os dados vão
| Atributo | Valores | Padrão |
|---|---|---|
action | Qualquer URL | A URL da página atual |
method | get, post, dialog | get |
enctype | application/x-www-form-urlencoded, multipart/form-data, text/plain | application/x-www-form-urlencoded |
Com method="get", os campos viram a query string da URL: um formulário de busca com name="q" vai para /search?q=blue+shoes. Isso é o certo para buscas e filtros, porque o resultado pode ir para os favoritos e ser compartilhado. Com method="post", os campos vão no corpo da requisição e não aparecem na barra de endereço nem no histórico. Use POST para tudo o que faz login, cria, altera ou apaga algo, e para senhas.
Um formulário com upload de arquivo (<input type="file">) precisa de method="post" e enctype="multipart/form-data", senão só o nome do arquivo é enviado. method="dialog" é para um formulário dentro de um <dialog>: enviar fecha o diálogo em vez de fazer uma requisição.
O que é enviado
Só os campos com name são enviados, e só quando não estão disabled. Aperte Submit e compare os campos com o que o formulário envia:
O formulário envia city, zip, source e action. O campo sem nome, o campo desativado e o checkbox desmarcado ficam de fora. Inputs ocultos são enviados, mas nunca aparecem, e o botão de envio manda o seu próprio name e value porque foi o botão usado.
Agrupando campos com fieldset e legend
<fieldset> desenha uma caixa em volta de campos relacionados, e <legend> é a sua legenda. Os leitores de tela anunciam a legenda quando o foco entra no grupo, e é isso que torna compreensível um conjunto de radio buttons como o de baixo: "Delivery, Standard, botão de opção".
disabled num fieldset desativa todos os campos dentro dele de uma vez, e nenhum deles é enviado. Remova o atributo e os campos de presente passam a funcionar.
Validação nativa: required, pattern e companhia
Os navegadores verificam estes atributos antes de enviar e mostram uma mensagem no primeiro campo que falha:
| Atributo | Verifica |
|---|---|
required | O campo não está vazio (um checkbox está marcado) |
type="email", type="url" | O valor parece um endereço de e-mail ou uma URL |
minlength, maxlength | Tamanho do texto |
min, max, step | Faixa de números e datas |
pattern | O valor inteiro corresponde a uma expressão regular |
:invalid e :valid estilizam os campos pelo estado. :user-invalid costuma ser melhor: só se aplica depois que o usuário alterou o campo e saiu dele, ou tentou enviar, então um formulário vazio não abre todo em vermelho.
Três coisas sobre pattern confundem muita gente. Ele precisa corresponder ao valor inteiro (não precisa de ^ nem $). Só roda quando o campo não está vazio, então combine com required. E a mensagem de erro do navegador é genérica, então descreva o formato num texto visível ao lado do campo. Chrome e Firefox acrescentam o texto do title à mensagem, mas é fácil não perceber.
Para desligar as verificações, por exemplo enquanto você testa a validação do servidor, adicione novalidate ao <form>. Um único botão de envio pode pulá-las com formnovalidate.
A validação do navegador existe para a comodidade do usuário. Qualquer pessoa pode editar a página ou enviar uma requisição sem ela, então o servidor precisa verificar cada valor de novo.
Mensagens personalizadas com setCustomValidity
Quando uma regra não pode ser escrita como atributo, como "as duas senhas precisam ser iguais", defina a mensagem pelo JavaScript. Um campo com uma mensagem personalizada não vazia é inválido; uma string vazia o torna válido de novo:
O campo de repetição não tem name, então só uma cópia da senha é enviada.
Tratando o envio no JavaScript
Para enviar o formulário sem sair da página, escute submit, chame preventDefault() e leia os campos com FormData. Escutar submit em vez do click de um botão pega todas as formas de envio, inclusive Enter, e só roda depois que a validação nativa passou:
Object.fromEntries(new FormData(form)) transforma os campos num objeto simples. Para campos que podem ter vários valores (checkboxes com o mesmo nome, um select múltiplo), use formData.getAll('name'), porque o objeto guarda só o último valor.
Erros comuns
- Campos sem
name. Eles ficam de fora dos dados enviados sem nenhum aviso. - Placeholders no lugar de labels. A dica some assim que o usuário digita. Use um
<label>. - Um
<button>semtypeusado para algo que não é enviar. Dentro de um formulário ele é um botão de envio. - Um formulário dentro de outro. Aninhar formulários é inválido; o navegador ignora a tag
<form>interna. - Escutar
clickno botão de envio em vez desubmitno formulário. Os envios pela tecla Enter se perdem. - Confiar na validação do navegador do lado do servidor. Valide de novo lá.
- GET para senhas. Elas vão parar na URL, no histórico e nos logs do servidor.
Perguntas frequentes
Como criar um formulário no HTML?
Envolva os campos em <form action="/signup" method="post">, dê a cada campo um name e um <label> e termine com <button type="submit">. Quando o formulário é enviado, o navegador manda cada par name=value para a URL do action.
Qual a diferença entre GET e POST num formulário?
method="get" (o padrão) coloca os campos na URL, como em /search?q=shoes, o que serve para buscas e filtros que devem poder ir para os favoritos. method="post" os envia no corpo da requisição, que é o que você quer para login, cadastro e tudo o que altera dados.
Por que um campo do meu formulário não está sendo enviado?
Ele não tem atributo name, ou está disabled. Só campos com nome e ativos são enviados. Um checkbox ou radio button desmarcado também fica totalmente de fora.
Para que servem fieldset e legend?
<fieldset> agrupa campos relacionados e <legend> é a legenda do grupo. Os leitores de tela anunciam a legenda quando o foco entra no grupo, e é isso que torna um grupo de radio buttons compreensível; disabled num fieldset desativa todos os campos dentro dele.
Como validar um formulário em HTML sem JavaScript?
Use atributos: required, type="email", minlength, maxlength, min, max e pattern. O navegador bloqueia o envio e mostra uma mensagem no primeiro campo inválido. Valide sempre no servidor também, porque essas verificações rodam no navegador do usuário e podem ser contornadas.
Como impedir que o formulário recarregue a página?
Escute o evento submit do formulário e chame event.preventDefault(), depois envie os dados você mesmo com fetch: form.addEventListener('submit', (e) => { e.preventDefault(); fetch(form.action, { method: 'POST', body: new FormData(form) }); }).