Contact Form
Em andamentoO formulário-padrão de contato, sobre as primitivas (E73): nome, e-mail, telefone, assunto (opcional), mensagem e o aceite de privacidade e contato (E154), em FormField, com o resumo de erros no topo quando o envio falha e a tela de sucesso em role="status".
- Função
- Formulário e ação
- Também chamado de
- fale conosco, formulário de contato, contato
- Mora em
- app/components/organisms/marketing/ContactForm.tsx
- Última mudança
- 2026-10-01
Prévia
A peça ao vivo, vinda da ficha, na largura escolhida. Em larguras fixas, ela roda num quadro do tamanho de uma tela de verdade.
Na largura da página: 0px
Variantes na ficha
Lidas da ficha no build, na ordem do palco. Cada uma abre sozinha, sem o styleguide em volta — é o endereço que o palco carrega.
Quando usar
Em página que precisa de um canal de contato genérico — e como o modelo de formulário que as equipes clonam.
Faça
- Passe
onEnviar: ele recebe{ nome, email, telefone, assunto, mensagem, aceite }— o telefone só em dígitos, com o DDD — e, no segundo argumento, os sinais de spam (E153). Sem ele, o formulário simula o envio (1,5s) — é a vitrine do padrão. - Leia os sinais no serviço que recebe (E153): com
campoIscaPreenchido, descarte; comrapidoDemais(menos detempoMinimo, 3s por padrão), marque para revisão em vez de descartar. - Escreva cada erro dizendo como acertar: "Informe um e-mail com @ e domínio".
- Marque o que não é obrigatório com "(opcional)", como o Assunto.
- Passe
hrefDaPoliticaehrefDosTermos: o aceite cita os dois, e os links abrem em nova aba — quem está no meio do formulário não perde o que escreveu.
Evite
- Voltar para a validação do navegador: ela fala a língua do sistema e não liga o erro ao campo.
- Avisar na tela que o envio parece spam: o robô aprende o que foi pego. O formulário segue o fluxo de sempre; quem decide é o serviço.
- Deixar o aceite marcado de saída, ou juntar nele uma autorização que não seja para responder a mensagem (LGPD: o consentimento é da pessoa, e por finalidade).
- Máscara no telefone: ela briga com quem cola o número e com o leitor de tela. O formulário aceita como a pessoa escreve e limpa no envio.
Quando não usar. Para só captar e-mail, a Newsletter ou a NewsletterStrip. Para conversa ao vivo, o ChatWindow.
Anatomia
As partes, na ordem em que o olho — e o teclado — passam.
- Resumo de erros — Quando o envio falha: "Há N problemas no formulário", com um link para cada campo (padrão GOV.UK), `role="alert"`, que recebe o foco.
- Nome e e-mail — FormField obrigatórios com o Input, `autocomplete="name"` e `"email"`. O rótulo é "E-mail" (era "E-mail corporativo", E154).
- Telefone — FormField obrigatório com o Input `type="tel"` e `autocomplete="tel"` (E154), a dica "Com DDD." visível; aceita parênteses, traço, espaço e +55, e valida 10 ou 11 dígitos.
- Assunto — FormField "(opcional)" com o Select e a sugestão "Selecione o motivo do contato", ao lado do telefone a partir do tablet.
- Mensagem — FormField obrigatório com o Textarea.
- Aceite — Grupo "Privacidade e contato" (FormField `as="fieldset"`) com o Checkbox `aceite`, desmarcado: "Li e aceito a Política de Privacidade e os Termos de Uso, e autorizo a Faculdade Phorte a responder pelo e-mail e pelo telefone informados" (E154).
- Enviar — Button primário grande, com o ícone de envio.
- Campo-isca — Proteção contra spam (E153): um campo fora da tela e `inert` — fora do Tab e da árvore de acessibilidade —, que só robô preenche. Com o tempo de preenchimento, vira os sinais do envio.
- Sucesso — `role="status"`: o visto, "Mensagem enviada!" (que recebe o foco) e "Enviar nova mensagem".
Estados
Os estados que a peça tem no código, e o que muda em cada um.
| Estado | O que muda |
|---|---|
| Erro | O resumo no topo e, em cada campo, o erro em pt-BR embaixo, aria-invalid e a borda vermelha — conferido no teste da ficha. |
| Enviando | O Button em isLoading ("Enviando mensagem…" para o leitor), aria-busy, focável. |
| Enviado | A tela de sucesso, com o foco no título (E102). |
| Sem o aceite | A caixa vermelha vazia; no envio, o erro do grupo e o link no resumo, que leva à caixa (E154). |
Comportamento
| Situação | O que acontece |
|---|---|
| Enviar com campos faltando | Não envia; o resumo aparece com o foco, e cada link leva ao campo — conferido no teste da ficha. |
| Enviar completo | Chama onEnviar (ou simula) e mostra o sucesso com o foco no título — conferido no teste da ficha. |
| "Enviar nova mensagem" | Limpa o formulário, recomeça o relógio da proteção contra spam e devolve o foco ao primeiro campo (E102). |
| Envio de robô | Campo-isca preenchido ou envio antes do tempo mínimo: o formulário segue igual, e os sinais acesos vão para onEnviar — conferido no teste da ficha. |
Relacionados
Como usar no código
A importação e o menor uso, lidos do arquivo. O … marca as props obrigatórias.
import { ContactForm } from '@/app/components/organisms/marketing/ContactForm';
<ContactForm />Propriedades
Lidas do código da peça no build — não escritas à mão.
| Prop | Tipo | Padrão | Obrigatória | Descrição |
|---|---|---|---|---|
onEnviar | (dados: DadosDeContato, sinais: SinaisDeSpam) => void | Promise<void> | — | não | Recebe os dados e envia (E73). Sem ela, o formulário simula o envio (1,5s) — é a vitrine do padrão de formulário, e a E102 construiu em cima dela o caminho do foco. O segundo argumento são os sinais de spam (E153): o campo-isca e o tempo de preenchimento. O formulário não bloqueia nada — quem decide é o serviço que recebe (ver app/lib/protecao-contra-spam.tsx). |
tempoMinimo | number | — | não | Tempo mínimo de preenchimento, em ms, para o sinal de "rápido demais" (E153). Padrão: 3000. |
hrefDaPolitica | string | — | não | Os endereços da Política de Privacidade e dos Termos de Uso, que o aceite cita (E154). Abrem em nova aba: quem está no meio do formulário não perde o que escreveu. Sem eles, o texto do aceite fica sem link. |
hrefDosTermos | string | — | não | — |
Tokens de cor
Os tokens semânticos que o código da peça usa, com o valor de hoje em app/globals.css.
| Token | Valor | Usado como |
|---|---|---|
--background | #FAFAFA | bg-background |
--border | #E5E5E5 | border-border |
--foreground | #1A1A1A | text-ink |
--muted-foreground | #595959 | text-muted-foreground |
--primary | #D42B2B | text-primary |
Teclado
| Tecla | Faz |
|---|---|
| Tab | Passa pelos links do resumo (se houver), por nome, e-mail, telefone, assunto, mensagem, a caixa do aceite e os links dele, e Enviar. O campo-isca fica fora (E153). |
| Espaço | Na caixa do aceite, marca e desmarca. |
| Enter | Num link do resumo, leva ao campo; no botão, envia. |
| ↑↓ | No Assunto, as teclas do `<select>`. |
Leitor de tela
O que é anunciado, e por quê.
- Cada erro fica ligado ao campo pelo FormField; o resumo é
role="alert"e recebe o foco a cada envio que falha. - O sucesso é
role="status"com o foco no título: quem usa leitor de tela ouve que enviou. - Os links do aceite terminam com "(abre em nova aba)" para quem ouve, e o nome do Checkbox é o texto inteiro do aceite — conferido no teste da ficha.
O que sustenta o estado
Esta peça usa formulario, regiaoViva. O estado dela é o de quem já foi ouvido com leitor de tela nesses padrões — e não uma passada sobre esta peça em específico.
Falta ouvir: formulario, regiaoViva — ver docs/a11y-screen-reader-checklist.md.
Status e recursos
| Tipo | Recurso | Status |
|---|---|---|
| Código | app/components/organisms/marketing/ContactForm.tsx | Disponível |
| Ficha | Storybook (abre em outra aba) | Disponível |
| Teste de acessibilidade | axe em npm run test | No gate de todo commit |
| Leitor de tela | Passada da E33 | Falta ouvir |
| Design | Figma | Desativado até a Fase 2 |
Histórico
Os últimos commits que tocaram o arquivo, lidos do git no build.
251416b2026-10-01E159: Testimonials — o vídeo toca dentro do cartão, YouTube e Vimeo
O histórico completo está no GitHub (abre em outra aba).