Frontends com Vibecoding · Capítulo 15 de 35 · 33 min
Construir formulários e estados de interação
A regra de cada campo passa a ser escrita uma vez para o navegador e para o servidor, e a tela mostra os quatro estados antes de a API existir.
Este capítulo faz parte do curso gratuito Frontends com Vibecoding.
Sem conferência no servidor, um cadastro aceita um telefone de dois dígitos, e a campanha de e-mail dispara meses depois para um endereço que nunca existiu. Validar um formulário é conferir cada campo antes de o dado entrar, e o formulário bem feito aplica a mesma regra nos dois lados.
Ele também desenha a tela do dado em quatro estados: vazio, carregando, erro e cheio. Quem aprova o cadastro perde venda por campo mal pensado, e regra escrita em dois lugares um dia discorda: o dado passa numa porta e falha na outra.
Por isso a descrição dos campos mora num arquivo só, importada pelas duas pontas, com os quatro estados provados num laboratório sem JavaScript.
Ao terminar, você sabe testar o formulário do site como um cliente que erra, e cobrar que ele explique cada erro perto do campo, com a mesma regra no navegador e no servidor. Tempo de leitura: cerca de 33 minutos, e o teste dos quatro estados no formulário da empresa, mais dez.
O schema, a ficha que descreve tamanho, formato e obrigatoriedade de cada campo, como a especificação de uma peça, vive num arquivo só e alimenta as duas barreiras. A primeira fica no navegador, o programa em que a pessoa preenche. A segunda fica no servidor, o computador da empresa que recebe o pedido e grava no banco.
Quando a conferência só roda no navegador, qualquer pedido enviado por fora da tela entra sem crítica, e é assim que um endereço inexistente chega ao banco. A barreira do navegador existe para conforto: avisa antes de a pessoa perder o trabalho de preencher tudo, e isso aparece na taxa de conclusão.
A do servidor existe para controle, porque roda onde quem preenche não alcança. Se você só puder escrever uma das duas, escreva a do servidor.
Ver como texto
O caminho do dado num formulário com descrição única. No topo, um único arquivo de schema descreve a forma dos dados e é importado pelas duas barreiras. Quem digita cruza primeiro a barreira do navegador, que existe para conforto, avisa na hora e melhora a conclusão; depois a barreira do servidor, que existe para controle, sustenta auditoria e é a última antes de o dado entrar no banco. Uma requisição enviada por fora da tela contorna a barreira do navegador e cai direto na do servidor, que confere de novo, e por isso a do navegador nunca é a única.
Há ainda a norma internacional de acessibilidade da web, o WCAG 2.2, que manda no acesso ao formulário. O critério 3.3.8 diz que teste de memória não pode ser a única forma de provar quem você é. Na prática, isso obriga a aceitar senha colada.
Campo de senha que bloqueia colar reprova nesse critério, porque empurra quem usa um cofre de senhas para uma senha fraca digitada à mão. Quem perde é o cliente que desiste do cadastro na terceira tentativa.
Essa ficha é escrita com a ajuda de um validador, a biblioteca que transforma a regra em código que roda nas duas pontas. Em 2026 são três nomes, e a diferença entre eles é pequena para quem está começando.
Escolha o Zod por padrão, porque o ecossistema inteiro já o entende e o agente devolve código com ele sem você pedir. Troque para o Valibot, que pesa 1,37 kB, quando o formulário abrir em rede lenta e cada kB pesar. Deixe o ArkType para quando a validação já estiver medida como gargalo.
Ver como texto
Árvore de decisão do validador. Todo formulário começa no Zod, que o ecossistema e o agente já entendem. Se o formulário abre em rede lenta e cada kB pesa, a escolha passa ao Valibot, de 1,37 kB. Se não, pergunta-se se a validação já foi medida como gargalo: com medição, ArkType; sem medição, o formulário fica no Zod.
A biblioteca de formulário guarda o que a pessoa digitou e conversa com a ficha de campos. Na maioria dos projetos React ela é o react-hook-form. Ela deixa o navegador guardar o valor digitado e só confere na hora de enviar, por isso a tela não pisca a cada tecla.
Junto dela vêm dois ganchos do React que sabem se o envio está rodando, e eles mostram o botão ocupado sem código extra. Botão que não avisa nada é o que faz a pessoa clicar três vezes e gerar três cadastros.
Formulário com etapas e campos que dependem uns dos outros pede o TanStack Form, e projetos em Angular resolvem o mesmo com os Signal Forms.
Parte do aviso visual dispensa JavaScript e vem pronta no navegador. O seletor :user-invalid pinta o campo errado só depois de a pessoa mexer nele, e o :user-valid pinta o certo. Formulário que abre com tudo em vermelho antes da primeira letra foi escrito com o seletor antigo, :invalid puro, e já nasce reclamando.
A propriedade field-sizing faz a caixa de texto crescer conforme a pessoa escreve, sem barra de rolagem nem script. A accent-color pinta caixa de marcação e botão de opção com a cor da marca numa linha, sem redesenhar o controle nem perder teclado e leitor de tela.
As três peças vêm do próprio navegador, por isso não pesam no carregamento e continuam funcionando quando o script falha.
Laboratório ao vivo: o formulário que avisa na hora certa
1. Cadastro do negócio
Cenário ilustrativo: nada é enviado. Preencha um campo e saia dele.
Onde você atende
Suporte: :user-valid, :user-invalid, field-sizing e accent-color são camada nativa consolidada no manual de setembro de 2026. Sem suporte, a linha de erro e de acerto não aparece, a caixa de texto ganha barra de rolagem e a marcação fica na cor do sistema.
2. Os quatro estados do dado
O que a lista mostra
Nenhum cadastro ainda
Cadastre o primeiro cliente e a lista começa aqui.
Buscando os cadastros
A lista não carregou
O servidor não respondeu em dez segundos. Confira a conexão e tente de novo.
Três cadastros
- Maria Aparecida Gonçalves da Silvahoje
- Padaria Pão da Serraontem
- Oficina do Tiãohá três dias
Suporte: :has() é camada nativa consolidada no manual de setembro de 2026. Sem suporte, as quatro vistas aparecem empilhadas; o esqueleto só brilha com movimento liberado no sistema.
O dado que a pessoa entregou volta para a tela dela em outra hora, quase sempre trazido por outro sistema. Buscar esse dado é pedi-lo ao servidor e esperar a resposta, e toda tela que faz isso tem quatro estados: vazio, carregando, erro e cheio.
Sozinho, o agente entrega um rascunho que desenha só o cheio, porque é o que aparece quando você testa com a própria conta, já cadastrada. O cliente novo abre a mesma tela vazia e não sabe o que fazer ali.
Busque no servidor por padrão, porque a página chega com o texto pronto para buscador e assistente, e a chave secreta fica fora do navegador. Suba a busca para o navegador só quando o dado mudar com o clique, como o carrinho.
No navegador, o TanStack Query e o SWR guardam o cache, a cópia local de um dado já buscado. Eles mostram essa cópia na hora e conferem o dado novo por trás, então a tela não fica em branco esperando.
Histórico consultado sempre, como as vendas do mês, cabe no IndexedDB, o banco de dados que mora dentro do navegador. A regra é a mesma: mostrar o antigo e conferir depois. O estado carregando mostra um esqueleto com a forma do conteúdo, em vez de uma roda girando sem fim.
O estado de erro mostra mensagem específica e um botão de tentar de novo, porque sem esse texto a tela só gira e a pessoa fecha a aba. O estado vazio explica o que fazer e oferece o primeiro passo.
Ver como texto
Quatro miniaturas da mesma tela. Vazio: explica o que fazer e oferece o botão do primeiro passo. Carregando: mostra um esqueleto com a forma do conteúdo em vez de uma roda girando sem fim. Erro: mostra o motivo e um botão de tentar de novo. Cheio: a lista com os dados, o único estado que o rascunho do agente costuma desenhar. Um quadro no rodapé resume onde a conversão se perde: tela vazia sem convite trava o cliente novo, e erro sem texto faz a pessoa fechar a aba.
Antes de aprovar o cadastro, peça a quem construiu para repetir o envio por fora da tela, com um telefone de dois dígitos. Se o servidor aceitar esse pedido, só existe a barreira do navegador e o cadastro está aberto.
Depois confira os quatro estados numa tela que busca dado e tente colar a senha no campo de acesso. Deu certo quando o servidor recusa o telefone curto, a tela mostra erro com botão de tentar de novo e a senha cola.
Pedir formulário, upload, lista arrastável e editor de texto ao agente
Com a regra de campo escrita uma vez e os quatro estados desenhados, o pedido ao agente pode nomear formulário, upload, lista arrastável e editor.
Pedido sem nome de biblioteca volta com uma opção que ninguém no time conhece, e pedido sem os quatro estados volta só com o caminho de sucesso. Por isso quem pede formulário, upload, lista arrastável ou editor de texto escreve o nome da peça e prova os quatro estados antes de aprovar.
Biblioteca aqui é uma peça de software pronta, escrita e mantida por outra pessoa, que você encaixa no site em vez de construir do zero. Cada uma resolve um problema, e trocar depois de publicado custa caro, por isso a escolha acontece antes do primeiro pedido ao agente.
Ver como texto
Comparação de dois pedidos ao agente. O pedido vago, faça o formulário de cadastro, volta com uma biblioteca que o time não conhece e só com o caminho de sucesso. O pedido nomeado, cadastro com react-hook-form e Zod, com vazio, carregando, erro e cheio, volta com a biblioteca que o time escolheu e com os quatro estados provados.
Você constrói e testa tudo isso antes de a API existir. API é a interface por onde um sistema entrega dado a outro, e aqui é o servidor que guarda os cadastros.
Um interceptador de rede, o MSW, responde no lugar do servidor verdadeiro enquanto o site está em desenvolvimento e nos testes, e fica de fora do site publicado. Com ele você força dez segundos de atraso e confere se a tela avisa em vez de girar sem fim.
Depois force um erro do servidor e, por fim, uma lista vazia. Os três caminhos aparecem numa tarde de teste, antes de qualquer chamado de suporte, e nenhum deles mostra tela branca.
O dado de exemplo leva nome brasileiro longo, como Maria Aparecida Gonçalves da Silva. É o texto longo que revela o cartão que estoura e o botão que quebra em duas linhas. Test User, com nove letras, esconde os dois defeitos.
Ver como texto
Antes e depois do interceptador de rede: sem ele você espera a API pronta e só testa o caminho de sucesso; com ele você força lentidão, erro e lista vazia numa tarde, antes de a API existir.
Lista que a pessoa reordena com o dedo pede o dnd-kit, que pesa seis kB e funciona pelo teclado, e merece atenção acima de mil itens. Quadro do tamanho do Trello, com colunas, pede o Pragmatic drag-and-drop.
Upload de arquivo grande pede o Uppy. O envio é resumível, quer dizer que retoma de onde parou quando a conexão cai. Sem isso, um extrato de 40 MB volta ao começo a cada queda da rede. Para a foto do perfil, o campo de arquivo do próprio navegador resolve.
Paleta de comandos, aviso passageiro e gaveta do rodapé são cmdk, Sonner e Vaul, o trio padrão das telas montadas com shadcn. Tour de primeiro acesso é o driver.js, leve e suficiente. O auto-animate anima a lista que muda, com uma linha de código.
A paleta abaixo usa o cmdk de verdade, com quarenta destinos de um painel fictício. Abra pelo botão ou por Ctrl K, digite fat e veja o filtro achar Faturamento do mês e Fatura em atraso pela palavra parcial. Depois solte o mouse: setas, Enter e Esc resolvem tudo, e o foco volta ao botão quando a paleta fecha.
O que decide é o painel embaixo da paleta. O cmdk entrega filtro, teclado e leitura por leitor de tela; o visual fica com o seu CSS. Com mais de uma dúzia de destinos, esse trabalho compensa. Com cinco ou seis, um menu comum ou o dialog nativo do navegador resolve, e você desce um degrau na tabela.
Editor de texto é a decisão mais cara da lista, porque trocar de editor depois de publicado significa reescrever o conteúdo já salvo. O TipTap é o padrão para site de conteúdo e para texto escrito a várias mãos. Ele vem sem visual pronto, então alguém do time desenha a barra de botões.
Quando duas pessoas editam o mesmo documento ao mesmo tempo, quem junta as duas versões é o Yjs, e o TipTap é o que melhor se encaixa nele. O Lexical serve rede social e aplicativo de celular, onde o desempenho com muito texto pesa mais.
Bloco no estilo Notion é o Plate ou o BlockNote, que já traz o arrastar de blocos pronto. Para escrever código na tela, o CodeMirror parte de 50 kB e o Monaco pesa de dois a cinco MB. O Monaco só se justifica para quem passa a tarde programando.
| Pedido | Biblioteca | Número que decide | Degrau abaixo |
|---|---|---|---|
| Formulário em React | react-hook-form com Zod v4 | inputs não controlados; Zod Mini 3,94 kB | formulário nativo com :user-invalid |
| Lista que a pessoa reordena | dnd-kit | 6 kB; atenção acima de mil itens | botões de subir e descer |
| Quadro no tamanho do Jira | Pragmatic drag-and-drop | colisão própria, escala Trello | dnd-kit |
| Upload grande ou de várias origens | Uppy 6 | resumível por TUS e S3 multipart | input de arquivo nativo |
| Paleta, aviso, gaveta no celular | cmdk, Sonner, Vaul | padrão das stacks com shadcn | dialog e popover nativos |
| Tour de primeiro acesso | driver.js | cerca de 5 kB | tela vazia que explica o primeiro passo |
| Tour com lógica condicional | Shepherd.js | licença dupla AGPL e comercial | driver.js |
| Lista que muda com animação | auto-animate | uma linha | transição CSS |
| Editor de CMS ou colaborativo | TipTap sobre ProseMirror | melhor integração com Yjs | textarea com field-sizing |
| Rede social, mensageria, React Native | Lexical (Meta) | desempenho em escala | TipTap |
| Blocos no estilo Notion | Plate ou BlockNote | shadcn; arrastar de blocos pronto | TipTap |
| Editor de código | CodeMirror 6 | a partir de 50 kB | Shiki, realce estático |
| IDE completa na tela | Monaco | 2 a 5 MB | CodeMirror 6 |
12 de 13 linhas
Tamanhos e versões da edição de setembro de 2026 do manual; o degrau abaixo é o que resolve sem a biblioteca.
As palavras da tela são parte do desenho. A skill frontend-design, o arquivo de instruções que o agente lê antes de desenhar, resume a regra em quatro pontos. Eles valem também para quem escreve o texto da tela à mão.
Nomeie pelo que a pessoa entende: ela gerencia avisos em vez de configurar um webhook, o aviso automático que um sistema manda a outro. O botão diz o que acontece, Salvar alterações, e nunca Enviar. A ação mantém o nome no fluxo inteiro, e Publicar gera um aviso que diz Publicado.
O erro explica o que houve e como resolver, sem pedir desculpa e sem vagueza. A tela vazia convida a agir, com o primeiro passo escrito. Tudo em tom conversado, verbo simples e sentence case, só a primeira letra maiúscula. Quem lê está no meio de outra coisa e não volta para decifrar rótulo.
Antes de aprovar a tela, peça o interceptador ligado só em desenvolvimento e nos testes, e force os três caminhos de falha. Releia cada botão e cada mensagem de erro pela régua da escrita.
Deu certo quando a demora mostra esqueleto, o erro mostra o que fazer, a lista vazia oferece o primeiro passo e nenhum botão diz apenas Enviar. Nomeie a biblioteca dentro do pedido, porque o nome é o que impede o agente de escolher por você.
Guia prático: página de captura com formulário e evento de medição
Formulário que valida e não mede deixa a campanha sem resposta: o anúncio gasta, o contato chega e ninguém sabe de qual peça ele veio. O roteiro abaixo junta a regra de campo que você já viu com o evento generate_lead do Google Analytics 4, o nome recomendado pelo Google para o envio de um formulário ou de um pedido de informação.
No Next.js, a documentação da versão 16.3.8 indica o pacote @next/third-parties: o componente GoogleAnalytics entra no layout raiz com o ID de medição, carrega depois da hidratação e a função sendGAEvent envia o evento. O pacote segue marcado como experimental. Quem já usa o Google Tag Manager configura o Analytics por ele, em vez de somar os dois.
O evento abre uma família. qualify_lead, working_lead e close_convert_lead registram o que acontece com o contato depois, e alimentam o relatório de aquisição de leads.
Coordenador de marketing de uma rede de clínicas odontológicas, com campanha de avaliação gratuita no Google e no Instagram
Saúde, agendamento por formulário
Dor
O painel de anúncios mostrava 180 conversões no mês e a recepção contava 95 pedidos. A página disparava o evento no carregamento da tela de agradecimento, que também abria por atualização e pelo botão de voltar.
Solução
Ele pediu ao agente o evento no envio aceito pelo servidor, uma vez por pedido, com a mesma ficha de campos no navegador e na rota. Conferiu no DebugView com três envios de teste e filtrou o próprio tráfego.
Resultado do exemplo
Os três envios apareceram três vezes, com o parâmetro de origem preenchido. A diferença entre painel e recepção passou a ser acompanhada toda semana.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Formulário de captura com um evento por envio aceito
Sete passos. A ordem importa: primeiro o dado entra certo, depois a medição conta uma vez.
Passo 1: Feche a lista de campos e a ficha única
No máximo quatro campos, cada um com tipo de teclado e autocomplete. A ficha em Zod alimenta o navegador e a rota do servidor, como no início.
Deu certo quando: Um envio por fora da tela, com telefone de dois dígitos, é recusado pelo servidor.
Erro comum: Pedir CPF, cargo e cidade numa página que só precisa de nome e WhatsApp.
Passo 2: Instale o Analytics pelo pacote do Next.js
npm install @next/third-parties@latest next@latest e o componente GoogleAnalytics com gaId no layout raiz. O ID de medição é público; chaves de API continuam no servidor.
Deu certo quando: A página carrega a etiqueta depois da hidratação e a troca de rota registra visualização sem código extra.
Erro comum: Somar GoogleAnalytics e Google Tag Manager com a mesma etiqueta e contar tudo em dobro.
Passo 3: Dispare generate_lead só quando o servidor aceitar
No retorno de sucesso da ação do formulário, chame sendGAEvent com o evento generate_lead e os parâmetros lead_source, value e currency quando houver valor estimado.
Deu certo quando: Um envio aceito gera um evento; um envio recusado pela validação não gera nenhum.
Erro comum: Disparar no clique do botão e contar como lead quem errou o e-mail.
Passo 4: Guarde a origem junto com o contato
Leia utm_source, utm_campaign e gclid da URL na entrada e envie com o formulário, em campo oculto, para o seu banco ou CRM.
Deu certo quando: O registro do contato mostra de qual campanha ele veio, sem depender do painel de anúncios.
Erro comum: Perder os parâmetros no redirecionamento para a página de agradecimento.
Passo 5: Teste a política de medição escolhida
Neste exercício, configure a medição de analytics para ocorrer somente depois do aceite e teste também a recusa. Essa configuração é a escolha didática do caso, não uma descrição de todos os modos de funcionamento do Consent Mode.
Deu certo quando: O pedido solicitado pelo formulário envia nos dois casos; a medição segue a política do exercício. Recusar uma newsletter opcional não bloqueia o pedido.
Erro comum: Condicionar o envio do formulário ao aceite de cookies e perder o contato.
Passo 6: Confira no DebugView
Ative o modo de depuração pelo Tag Assistant e abra Administrador, Exibição de dados, DebugView. Faça três envios de teste e clique no evento para ver os parâmetros.
Deu certo quando: Três eventos generate_lead na coluna dos últimos 60 segundos, cada um com a origem preenchida.
Erro comum: Procurar o evento com o bloqueador de anúncios ligado ou sem ter aceitado os cookies, e concluir que a instalação falhou.
Passo 7: Marque como evento principal e filtre o tráfego interno
No GA4, marque generate_lead como evento principal e filtre o tráfego de desenvolvimento. Na plataforma de anúncios, importe o mesmo evento.
Deu certo quando: A contagem do painel acompanha a contagem da base de contatos, com diferença explicada.
Erro comum: Deixar os envios de teste da equipe dentro do número da campanha.
No fim você tem: Uma página de captura com validação nos dois lados, um evento por envio aceito, origem gravada com o contato e conferência feita no DebugView.
Diagnosticar um formulário que parece funcionar, mas perde solicitações
No caso fictício da Escola Horizonte, a confirmação aparece ao clicar, mesmo quando o servidor recusa o envio. Este laboratório acrescenta testes de falha ao guia de medição: só existe conversão técnica quando o pedido foi aceito. Use a prévia didática e registros fictícios, com envio de mensagens e integrações comerciais desligados.
A documentação atual do Lovable permite pedir browser testing no chat e acompanhar as ações em Details. O anúncio de rascunhos de 09/09/2026 alerta que eles compartilham dados com o projeto: copiar a tela não isola o banco. No Chrome, a atualização publicada em 22/09/2026 reorganizou Device Mode e Settings > Devices por formato de aparelho. Use esses recursos para conferir a experiência, sem tratar emulação como substituta do teste num celular.
Executar o percurso completo, incluindo falhas
Prepare as respostas de erro na cópia didática, construa primeiro e peça o teste numa mensagem seguinte. Registre o que foi observado, inclusive o que ficou bloqueado.
Passo 1: Prepare um destino de teste separado
Peça ao agente um modo de teste que aceite ou recuse a solicitação sem gravar contatos reais. Use Aluna Teste e aluna@example.com. Confirme que nenhuma automação envia e-mail, WhatsApp ou pedido ao CRM.
Deu certo quando: Você consegue indicar onde o dado fictício será registrado e como observar a resposta.
Erro comum: Presumir que um rascunho isolou o banco. Se o destino real continuar conectado, substitua-o antes do envio.
Passo 2: Reproduza erro, envio e confirmação
No chat, peça browser testing com campo vazio, e-mail inválido, resposta recusada, envio aceito e repetição do clique. Abra o cartão de atividade e Details para ler URL, ações e resultados.
Deu certo quando: Cada cenário tem resultado observado. A mensagem de sucesso só aparece depois da aceitação.
Erro comum: O agente mostra apenas uma captura final. Peça o percurso de cada cenário e marque como não verificado o que não executou.
Passo 3: Confira a tela estreita e o teclado
Abra DevTools e ative Device Mode. Selecione um aparelho no grupo Mobile e repita o percurso; depois use somente Tab, Shift+Tab e Enter. Num celular real, abra o formulário com o teclado visível e procure o botão de envio.
Deu certo quando: Rótulos e erros permanecem legíveis, o foco aparece e o botão pode ser alcançado sem rolagem lateral.
Erro comum: A prévia parece boa, mas o teclado cobre a ação. Ajuste espaço e rolagem e repita no aparelho.
Passo 4: Concilie aceitação e evento de conversão
No destino de teste e no depurador da medição, compare o mesmo envio. Com medição consentida neste exercício, exija um registro gravado e um evento para a solicitação aceita. Resposta HTTP 200 sem gravação, validação recusada e falha de envio não contam como lead.
Deu certo quando: Repetir o clique ou atualizar a confirmação não cria um segundo contato nem uma segunda conversão.
Erro comum: O painel conta o clique antes da resposta. Mova o disparo para o aceite e proteja a gravação contra repetição.
Passo 5: Revise acessibilidade e repita após a correção
Confira manualmente rótulos, foco, mensagem de erro associada ao campo e confirmação anunciada pelo leitor de tela. Faça a avaliação de contraste do capítulo; browser testing não avalia nuances de cor com confiabilidade.
Deu certo quando: A ficha guarda cenário, esperado, observado, evidência e data da repetição depois da correção.
Erro comum: A IA declara tudo acessível sem conferir teclado e leitor de tela. Mantenha essas verificações como pendentes até executá-las.
No fim você tem: Um registro de aceite do formulário com caminhos de sucesso, falha e repetição. Esse registro valida o funcionamento; a taxa de conversão será medida com tráfego real.

Ver como texto
Captura oficial do Chrome DevTools com os aparelhos de emulação do Device Mode organizados por formato, incluindo o grupo Mobile.
| Sintoma observado | Causa a investigar | Movimento de saída |
|---|---|---|
| Confirmação aparece mesmo com resposta recusada | A tela muda no clique, antes do retorno do servidor | Mostrar sucesso só após o aceite; no erro, preservar o preenchimento e permitir nova tentativa |
| O mesmo pedido aparece duas vezes | Reenvio durante espera ou gravação sem proteção contra repetição | Bloquear novo clique durante o envio e pedir ao agente uma chave de operação que o servidor reconheça no reenvio |
| O erro fica vermelho, mas não é anunciado | A mensagem não está associada ao campo ou o aviso não chega ao leitor de tela | Associar rótulo e mensagem ao campo; conferir foco e anúncio com teclado e leitor de tela |
Avaliar o aceite do formulário antes da publicação
Critério de pronto
0/4A Escola Horizonte termina com uma ficha de testes que permite repetir a conferência após trocar o título ou o formulário. Na campanha real, a equipe segue o guia de medição para observar o resultado. Um envio de teste bem-sucedido prova o percurso técnico; decidir qual versão converte melhor continua dependendo do experimento e da amostra definidos antes do tráfego.

Ver como texto
Tela de demonstração do DebugView no Google Analytics. À esquerda, o menu de administração com o item DebugView selecionado. No centro, a linha do tempo dos últimos minutos e a lista de eventos dos últimos segundos, como view_item_list, user_engagement e scroll. À direita, o quadro Top Events com a contagem de cada evento nos últimos 30 minutos.
Guia prático: escolher o canal de captura pelo setor
A dúvida de todo projeto de captação é se o botão abre um formulário, uma conversa ou uma agenda. Os templates medidos em 07/10/2026 mostram que o setor já responde boa parte. Dos 10 templates com WhatsApp, 8 são os de negócio local em português; nos 5 de advocacia, 4 usam WhatsApp com mensagem pré-escrita, diferente para cada serviço, e só o mais institucional usa "Agende uma consulta". Nenhum dos 12 templates premium em português tem um elemento form. Já os de SaaS, em inglês, chamam para teste grátis ou demonstração.
| Canal | Quando serve | Como medir |
|---|---|---|
| WhatsApp com mensagem pronta | Serviço local, dúvida que pede conversa, ticket médio que pede confiança | Clique por botão, com a origem na própria mensagem |
| Formulário curto | Orçamento com dados fixos, material para baixar, lista de espera | Envio com sucesso, nunca o carregamento da página de obrigado |
| Agendamento | Consulta, demonstração, visita com horário | Horário confirmado na agenda |
A biblioteca de 1.451 componentes mostra o outro lado. Há 126 componentes de formulário, mas só 19 deles funcionam sem pacote extra; pedir "um formulário bonito" costuma trazer biblioteca de animação para três campos. Formulário é conteúdo, não efeito: o que decide o resultado são as perguntas, os rótulos e a mensagem de erro, não a borda que brilha.
Troque os botões de contato desta página por links de WhatsApp.
Número: [55 + DDD + número, só dígitos], lido de um único lugar no código.
Para cada botão, uma mensagem pré-escrita diferente:
- Topo: "Olá! Vim pelo site e quero saber sobre [serviço principal]."
- Cada serviço: "Olá! Vim pela página e quero falar sobre [nome do serviço]."
- Dúvidas: "Olá! Li as dúvidas do site e ainda quero perguntar sobre [tema]."
Regras:
- Monte o endereço com wa.me e o texto codificado por encodeURIComponent.
- Cada botão envia um evento de clique com o nome da seção.
- Sem formulário nesta página. Liste os links prontos para eu testar.Do botão genérico à captura que diz de onde veio
Cinco passos para decidir o canal e medir o que ele traz.
Passo 1: Pergunte ao atendimento como o cliente prefere falar
Quem atende sabe se o cliente pede preço no WhatsApp, prefere preencher e esperar ou quer escolher um horário. Use a tabela acima como ponto de partida e a resposta do atendimento para decidir.
Deu certo quando: Você tem um canal principal escolhido e o motivo escrito numa frase.
Erro comum: Pôr formulário, WhatsApp e agenda no mesmo botão e dividir a decisão do cliente em três.
Passo 2: Escreva uma mensagem por ponto de entrada
No WhatsApp, a mensagem pré-escrita diz de qual seção e de qual serviço o contato veio. No formulário, um campo oculto guarda a mesma informação.
Deu certo quando: Quem atende sabe, pela primeira mensagem, qual serviço o cliente estava lendo.
Erro comum: Usar a mesma mensagem em todos os botões e perder a origem do contato.
Passo 3: Se for formulário, peça só o que você usa
Cada campo precisa de um uso no atendimento. Rótulo visível acima do campo, erro escrito ao lado dele e estado de envio claro. Nada de biblioteca de animação para isso.
Deu certo quando: O formulário tem no máximo os campos que o atendimento usa, e cada erro diz o que corrigir.
Erro comum: Pedir CPF e endereço completo para mandar um material gratuito.
Passo 4: Meça o clique e o resultado, separados
O clique no botão é um evento; a conversa iniciada, o envio aceito e o horário confirmado são outro. Registre os dois e compare semanalmente.
Deu certo quando: Você sabe quantos cliques viraram conversa, envio ou horário marcado.
Erro comum: Contar o clique no WhatsApp como contato fechado.
Passo 5: Teste cada canal no celular antes de publicar
Toque em cada botão no celular, confira se o WhatsApp abre no número certo com a mensagem certa, envie um formulário de teste e marque um horário de teste.
Deu certo quando: Todos os botões abrem o canal certo, com o texto certo, no celular.
Erro comum: Publicar com o número de exemplo que veio no template.
No fim você tem: Um canal de captura escolhido pelo setor e pelo atendimento, com a origem de cada contato registrada e o clique separado do resultado.
Advogado previdenciário em Campinas que atende aposentadoria, benefício por incapacidade e revisão
Advocacia, captação local
Dor
O site tinha um formulário de seis campos que quase ninguém preenchia, e os clientes ligavam sem dizer qual página tinham lido.
Solução
Ele trocou o formulário por botões de WhatsApp com uma mensagem diferente para cada área de atuação e passou a registrar o clique de cada botão com o nome da seção.
Resultado do exemplo
A secretária passou a saber o assunto da conversa na primeira mensagem, e o escritório viu quais áreas da página geravam contato.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Uma regra, escrita uma vez, vale nos dois lados
O formulário confere o dado duas vezes: no navegador, para avisar rápido, e no servidor, para não aceitar dado errado de quem burla a tela. Quando as duas regras são escritas em lugares diferentes, elas divergem. Bibliotecas como Zod deixam escrever a regra uma vez; React Hook Form cuida de mostrar o erro na tela.

Ver como texto
Página inicial do React Hook Form em fundo escuro, com o título The React form library without the friction, o subtítulo que a descreve como biblioteca de formulários com validação fácil, os botões Get Started e API Documentation, o comando npm install react-hook-form e uma área Quick start com modos de validação (onSubmit, onBlur, onChange) e regras como firstName required e email pattern.

Ver como texto
Página inicial da documentação do Zod com um aviso no topo, Zod 4.6 is out, o selo New Zod 4.6, o logotipo azul, a descrição TypeScript-first schema validation with static type inference, selos de licença MIT e de 222 milhões de downloads por semana, e a frase Zod 4 is stable.

Ver como texto
Guia Client-side form validation do MDN Web Docs, com o texto que explica que a validação no navegador confere se os campos obrigatórios estão preenchidos no formato certo antes do envio, uma tabela de pré-requisitos e objetivo e a frase final, em itálico, de que a validação no navegador não deve ser tratada como medida de segurança completa.
O que mudou. O React Hook Form lançou em 11/09/2026 a versão 7.88, com um componente próprio para mostrar mensagem de erro, e em 23/10 a 7.91, além de uma versão 8 ainda em teste. O Zod chegou à 4.6 em 09/09/2026. As duas peças seguem ativas, o que pesa a favor delas na escolha.
Onde mora a regra de cada campo
Regra escrita duas vezes
Coluna a evitar
- O navegador aceita um CPF que o servidor recusa
- A mensagem da tela diz uma coisa e o erro do servidor, outra
- Cada mudança de regra exige lembrar dos dois lugares
Regra escrita uma vez, usada nos dois lados
Coluna recomendada
- Um esquema, como os do Zod, descreve o campo uma vez
- A tela avisa rápido e o servidor confere com a mesma regra
- Mudar a regra é uma edição, revisada uma vez
Faça agora: teste o formulário como um cliente que erra
Passo 1: Abra o formulário de contato ou de cadastro do site e clique em enviar sem preencher nada.
Deu certo quando: Cada campo obrigatório mostra uma mensagem perto dele.
Erro comum: Mensagem única no topo, que obriga a pessoa a procurar o campo errado.
Passo 2: Digite um e-mail sem @ e saia do campo.
Deu certo quando: O aviso aparece ao sair do campo, antes do envio.
Passo 3: Preencha certo e envie.
Deu certo quando: O botão mostra que está enviando e não aceita um segundo clique.
Passo 4: Confira a tela final.
Deu certo quando: Uma mensagem diz o que acontece agora e em quanto tempo.
Erro comum: A página só limpa os campos, sem confirmar nada.
No fim você tem: O retrato dos quatro estados do formulário: vazio, erro, enviando e sucesso.
Os quatro estados do formulário
Conferido no formulário da empresa
0/5Aplicar os recursos ao projeto
Ver como texto
O formulário precisa de saídas visíveis
Uma ação de envio parte de dados editáveis, passa por andamento e pode terminar em confirmação ou erro. As duas saídas mantêm uma mensagem identificável.
Ver como texto
Fluxo vertical do pipe do Valibot para o campo quantidade. A entrada passa por v.number, que confere se é número; depois por v.integer, que confere se é inteiro; depois por v.minValue(1), que confere se é 1 ou mais. Passando nas três, success é verdadeiro e a tela usa output. Qualquer etapa que falha manda o caso para issues, que aponta o campo certo em vez de um erro genérico.
Seu caderno neste capítulo
Abrir o caderno completoSelecione um trecho do capítulo para destacar ou anotar. Nos vídeos e áudios, use Anotar este momento. No teclado, selecione com Shift e as setas e use Alt+Shift+D para destacar ou Alt+Shift+N para anotar.
Salvo neste navegador. Entre na sua conta para levar o caderno a outros aparelhos.
Entre na sua conta para compartilhar o que aprendeu e convidar alguém para estudar com você.
Conexões deste capítulo
Veja o que estudar antes e para onde seguir depois, explore os conceitos e compare abordagens em outros cursos. Sugestões marcadas como “sugerido pelo grafo” vêm dos assuntos em comum, não do índice do curso.
Estude antes
- CursoClaude Code: do zero à prática
- Consulte um termo e veja como usá-losugerido pelo grafoApresenta os conceitos “Hidratação” e “Schema.org”, usados em “Construir formulários e estados de interação”.
- CursoSíntese e didática com IAsugerido pelo grafoDepois de escolher a informação essencial e desenhar hierarquia, gráficos e fluxos compreensíveis, o aluno pode aplicar esses critérios às interfaces do curso de frontend. A ponte conecta clareza da mensagem, acessibilidade e decisões de apresentação.
- CursoNode.js: JavaScript no Servidorsugerido pelo grafo9 capítulos de “Frontends com Vibecoding” usam conceitos apresentados em “Node.js: JavaScript no Servidor”.
Conceitos deste capítulo
O mesmo assunto em outros cursos
- Node.js: JavaScript no ServidorNavegador e servidor: quem faz cada parteExaminar conexões de Navegador e servidor: quem faz cada parte
- SEO programáticoImpedir que dados inválidos virem páginasExaminar conexões de Impedir que dados inválidos virem páginas
- Vibecoding para SEOCaptação de leads: o que RD Station, Hotmart e HubSpot ensinamExaminar conexões de Captação de leads: o que RD Station, Hotmart e HubSpot ensinam
- Astra profundoProjetar o que o visitante vê da escolha à confirmaçãoExaminar conexões de Projetar o que o visitante vê da escolha à confirmação
Terminou a leitura?
Você está aqui: capítulo 15 de 35
0 de 35 concluídos
- Próximo · Capítulo 16 de 35 · 32 minPublicar conteúdo encontrável em vários idiomasLer o capítulo 16 sem concluir
Marque como concluído para o capítulo contar no seu painel e no certificado.
- Anterior · Capítulo 14 de 35 · 17 minConstruir profundidade e dirigir a montagem de vídeoVoltar para o capítulo 14
Leve uma ideia para a prática
Escolha uma atividade no painel e volte a este curso quando quiser.
Atividades e evolução ficam reunidas no painel da sua conta.
Laboratórios ao vivo deste curso
Cada laboratório monta a biblioteca real dentro da aula, com controles para você mexer e o código do exemplo para copiar. O texto de reserva descreve a demonstração para quem lê sem JavaScript. O link abre o capítulo já no ponto do laboratório.
Base UI
Prenda o foco num diálogo sem escrever o comportamento
Abra a janela Agendar visita, percorra os campos com Tab, feche com Esc e acompanhe no painel onde o foco está e para onde ele volta.
Pacote
Abrir no capítuloConstruir componentes, usar o registro e publicar o catálogo@base-ui/reactLucide e Iconify
Mantenha uma família de ícones coerente e nomeie cada botão
Mude tamanho, traço e cor da barra, veja o símbolo do Iconify acompanhar o Lucide e rode a auditoria de nomes acessíveis.
Pacote
Abrir no capítuloProjetar uma linguagem de ícones e ilustraçãolucide-react, @iconify/reactMotion
Testar os três sinais que autorizam o terceiro degrau
Reproduza a entrada em sequência, aperte o botão com mola e arraste o cartão; ajuste rigidez e amortecimento e veja o que muda.
Pacote
Abrir no capítuloProjetar movimento, assinatura e narrativas por rolagemmotionVidstack
Ver o que separa um player de um vídeo cru
Dê o play, troque a velocidade e ligue a legenda; o painel ao lado mostra o estado que o player publica e que a etiqueta crua esconde.
Pacote
Abrir no capítuloProjetar movimento, assinatura e narrativas por rolagem@vidstack/reactcmdk
Achar um destino entre quarenta digitando três letras
Abra a paleta, digite fat e escolha um item só pelo teclado; o painel embaixo conta o que o filtro deixou passar e quanto tempo levou.
Pacote
Abrir no capítuloConstruir formulários e estados de interaçãocmdknumber-flow
Animar indicadores que mudam ao vivo com formato pt-BR
Veja três indicadores fictícios rolarem a cada troca e compare com o número em texto puro. Pause, reinicie e observe o separador de milhar.
Pacote
Abrir no capítuloProjetar gráficos e painéis pela decisão@number-flow/reactApache ECharts
Medir o custo de desenhar 200 mil pontos com o ECharts
Troque o tipo de gráfico e o volume de pontos, leia o tempo de desenho e alterne o eixo em zero. Mude o tema do site e veja as cores refazerem.
Pacote
Abrir no capítuloProjetar gráficos e painéis pela decisãoechartsApache ECharts
Painel grande com visões coordenadas
Clique num canal para filtrar todas as visões, troque a densidade entre 6, 9 e 12 visões, alterne tema e movimento e abra a tela cheia.
Pacote
Abrir no capítuloProjetar gráficos e painéis pela decisãoechartssharp e svgo
Escolher a variante certa da imagem e conferir o teto de 150 KB
Arraste a largura da tela simulada, troque a densidade entre 1x e 2x e veja qual arquivo o navegador escolhe, quanto ele pesa e se cabe no orçamento.
Pacote
Abrir no capítuloValidar desempenho, autenticação e segurançasharp, svgoReact Flow (xyflow)
Disparar um pedido e ver o orquestrador distribuir, conferir e responder
Alterne paralelo e sequencial, ligue e desligue a verificação e use a medição real; observe o tempo de parede em cada combinação.
Pacote
Abrir no capítuloConstruir as cenas do orquestrador, do paralelismo e do robô@xyflow/reactGSAP, Web Workers e number-flow
Dividir mil tarefas entre trabalhadores reais e correr três ritmos de geração
Execute com um trabalhador, depois com quatro e oito, e compare o tempo; em seguida percorra a corrida e separe a espera inicial do ritmo.
Pacote
Abrir no capítuloConstruir as cenas do orquestrador, do paralelismo e do robôgsap, @number-flow/reactThree.js com React Three Fiber, drei, Rapier e XR
Carregar o braço robótico, ver a física trabalhar e entrar na cena com o visor
Carregue a cena pelo botão, inicie o ciclo, mostre os ângulos das juntas, troque a câmera e a velocidade; com visor, entre em realidade virtual.
Pacote
Abrir no capítuloConstruir as cenas do orquestrador, do paralelismo e do robôthree, @react-three/fiber, @react-three/drei, @react-three/rapier, @react-three/xrMotion
Ver quatro agentes em raias trocando mensagens e a revisão devolvendo um trecho
Reproduza os 60 s de modelo, percorra o tempo pelo controle e esconda as mensagens para comparar a leitura; repare no tempo de parede contra a soma.
Pacote
Abrir no capítuloEspecificar, medir e produzir as cenas da máquinamotionMediaRecorder, Canvas 2D e Long Animation Frames (plataforma)
Medir o quadro da cena e gravar seis segundos dela em vídeo
Suba as partículas, force um bloqueio de 300 ms e leia o medidor; depois grave seis segundos, veja o codec escolhido e baixe o arquivo.
Pacote
Abrir no capítuloEspecificar, medir e produzir as cenas da máquinasem pacotesigma.js, graphology com ForceAtlas2 e cosmos.gl
Ver o grafo real do curso e um grafo de milhares de nós se organizarem em aglomerados
Rode o layout no grafo real, passe o mouse pelos nós e busque uma entidade; troque para 20 mil nós e leia o medidor; depois carregue o modo massivo na placa de vídeo.
Pacote
Abrir no capítuloAnimar um grafo de conhecimento amplo em movimentosigma, graphology, graphology-layout-forceatlas2, graphology-generators, @cosmos.gl/graph
Capítulos vizinhos em Frontends com Vibecoding
- 13Preparar imagens, ícones e vídeo para a web
- 14Construir profundidade e dirigir a montagem de vídeo
- 15Construir formulários e estados de interação
- 16Publicar conteúdo encontrável em vários idiomas
- 17Projetar gráficos e painéis pela decisão