Frontends com Vibecoding · Capítulo 13 de 33 · 29 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. Para marcar como concluído e salvar o progresso, abra este capítulo na página do curso.
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.
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.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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.
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.
A demonstração monta uma paleta de comandos com o cmdk sobre um painel de operações fictício de quarenta destinos em quatro grupos: telas, relatórios, ações e ajuda. Você abre pelo botão Buscar ou por Ctrl K, digita parte de um nome, navega com as setas e confirma com Enter. Um painel embaixo mostra quantos itens sobraram, a palavra digitada e o tempo que o filtro levou.
A demonstração interativa carrega quando este trecho entra na tela.
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.
O nome certo para cada pedido
| 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 |
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 deste capítulo 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
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 deste capítulo.
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: Respeite o consentimento antes de medir
Com modo de consentimento ativo, o evento só aparece depois do aceite. Teste os dois caminhos: com aceite e com recusa.
Deu certo quando: O formulário envia nos dois casos, e a medição só acontece no aceite.
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.

Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
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
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.
Aplicar os recursos ao projeto
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
React Hook Form organiza valores, validação e envio de formulários em React. O registro liga cada campo ao formulário e deixa você continuar usando campos de HTML comuns. Ele corta o código de ligação; rótulo claro, mensagem colada ao campo e regra no servidor continuam com você.
Pegue register, handleSubmit e formState de useForm. No campo de e-mail, espalhe register('email', { required: 'Informe o e-mail' }) e ligue um label ao id dele. O formulário chama handleSubmit(enviar), e enviar espera a resposta do serviço. Mostre formState.errors.email?.message logo abaixo do campo, ligado a ele por aria-describedby.
Mande o formulário vazio, corrija o campo e depois force um erro no serviço. O que a pessoa digitou tem de continuar ali para a segunda tentativa. Use isSubmitting para avisar que está enviando, sem cantar vitória antes da resposta. Formato válido não prova que o endereço existe.
Zod confere os dados no momento em que eles chegam, a partir de um schema, a descrição do formato aceito. O mesmo schema pode gerar os tipos e fazer a validação, sem dois lugares para manter. Ajuda nas bordas: formulário, planilha importada ou resposta de serviço de fora.
Defina Pedido = z.object({ quantidade: z.number().int().positive(), produto: z.string().min(1) }). Chame Pedido.safeParse(dados) e olhe success. Deu certo? Use data. Deu errado? Transforme os caminhos de error.issues em mensagens ao lado dos campos. Valor de FormData chega como texto e precisa virar número antes de entrar no schema.
Teste quantidade negativa, campo vazio e número quebrado. Converter texto vazio sem cuidado vira zero e passa batido; decida e anote o tratamento. Objeto válido ainda pode apontar para um produto que aquele cliente não pode comprar. Faça essa checagem no serviço, depois da checagem de formato.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Valibot descreve validações com funções que se encaixam umas nas outras. Você importa só as peças que usa e confere se a ferramenta de construção joga o resto fora. Vale quando o peso que chega ao navegador importa, desde que você meça o pacote real e suas dependências.
Importe as funções pelo apelido v e monte v.object({ email: v.pipe(v.string(), v.email()), quantidade: v.pipe(v.number(), v.integer(), v.minValue(1)) }). Rode v.safeParse(esquema, dados). Se success for verdadeiro, use output; se não, ligue issues aos campos. O pipe aplica cada checagem sobre o valor que a etapa anterior devolveu.
Mande texto no lugar da quantidade e um e-mail fora de formato. A mensagem precisa apontar o campo certo, não um erro genérico. Nunca escolha pela promessa de tamanho: compare a saída de produção com as mesmas regras. Repita a validação no serviço e trate permissão à parte.
Tiptap dá a base de um editor de texto rico, montado sobre o ProseMirror, com extensões que definem o que o usuário pode escrever. O visual fica por sua conta. Vale quando a pessoa precisa de lista, título e negrito; uma anotação curta cabe muito bem num textarea comum.
Crie Editor de @tiptap/core com element apontando para a área de edição, extensions com StarterKit e content com um parágrafo inicial. Um botão roda editor.chain().focus().toggleBold().run(). Para salvar, pegue editor.getJSON() e anote a versão das extensões que vão reabrir esse conteúdo depois. Sem ela, o texto volta torto.
Edite, salve e reabra o documento; teste seleção, desfazer e navegação por teclado. Trocar as extensões muda o que o editor aceita e pode comer formatação antiga. HTML que entra e sai precisa de tratamento antes de aparecer fora do editor. Colaboração e serviço pago têm configuração própria; não criam permissão.
Laboratório visual: construir formulários e estados de interação
Validação, envio, confirmação e recuperação
Escolha um horário
Os horários demonstrativos são 14h e 16h. Nenhuma reserva será enviada.
Selecione cada estado acima. A simulação permanece em “Enviando” para permitir a inspeção; escolha “Confirmado” ou “Erro” para examinar as saídas.
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
Explore os conceitos e compare abordagens em outros cursos. As conexões indicam assuntos relacionados; a sequência de estudo continua no índice do curso.
Conceitos deste capítulo
O mesmo assunto em outros cursos
- Bastidores: Como Este Portal Foi ConstruídoConta, progresso, certificado e gamificaçãoExaminar conexões de Conta, progresso, certificado e gamificação
- SEO ProgramáticoBloquear a publicação de registro inválidoExaminar conexões de Bloquear a publicação de registro inválido
- MCP com Chrome: Automação com IAFazer o agente ler a página em texto em vez de fotografarExaminar conexões de Fazer o agente ler a página em texto em vez de fotografar
- Software e IA para executivosResponder ao cliente agora e deixar o resto para depoisExaminar conexões de Responder ao cliente agora e deixar o resto para depois
Voltar ao capítulo anterior: Construir profundidade e dirigir a montagem de vídeo
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ã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
- 11Preparar imagens, ícones e vídeo para a web
- 12Construir profundidade e dirigir a montagem de vídeo
- 13Construir formulários e estados de interação
- 14Publicar conteúdo encontrável em vários idiomas
- 15Projetar gráficos e painéis pela decisão