Table of Contents
Por que formulários multi-passo são uma escolha inteligente para coleta de dados amigável
Formas longas e de página única muitas vezes frustram os usuários e levam a taxas de abandono mais elevadas. Quebrar um formulário em etapas lógicas – uma tela de cada vez – reduz a carga cognitiva e faz o processo se sentir mais manejável. Formas múltiplas orientam os usuários através de cada informação sem sobrepujá-los, o que melhora as taxas de preenchimento e a qualidade dos dados.
De uma perspectiva técnica, o JavaScript oferece-lhe a flexibilidade para esconder e mostrar secções, validar a entrada antes de avançar e fornecer feedback imediato. Quando combinado com a validação adequada, os formulários multi-step podem garantir que apenas dados limpos e precisos sejam enviados ao seu servidor.
Neste artigo, você aprenderá a construir um formulário multi-passo robusto usando o JavaScript de baunilha, incluindo navegação, validação do lado do cliente, indicadores de progresso e melhores práticas de acessibilidade.
Estrutura de base de um formulário multi-passo
Cada forma multi-passo segue um padrão semelhante:
- A forma recipiente que envolve todos os passos
- Seções múltiplas de passos – cada passo é um que se torna visível ou oculto
- Botões de navegação – “Next” e “Anterior” para se mover entre passos
- Lógica de validação – verifica se os campos na etapa atual são válidos antes de permitir que o usuário prossiga
Você também pode adicionar um indicador de progresso (por exemplo, números de passos ou uma barra de progresso) para mostrar aos usuários onde eles estão e quanto resta.
Construindo a Shell HTML
Comece com uma estrutura HTML limpa. Cada passo é um com uma classe de . Apenas o primeiro passo é visível por padrão; os outros estão ocultos com .
<form id="multiStepForm">
<!-- Step 1: Personal Information -->
<div class="step active" id="step1">
<h3>Step 1: Personal Information</h3>
<label for="name">Full Name</label>
<input type="text" id="name" name="name" required />
<button type="button" class="next-btn">Next</button>
</div>
<!-- Step 2: Contact Details -->
<div class="step" id="step2" style="display:none">
<h3>Step 2: Contact Details</h3>
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required />
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone" />
<button type="button" class="prev-btn">Previous</button>
<button type="button" class="next-btn">Next</button>
</div>
<!-- Step 3: Confirmation -->
<div class="step" id="step3" style="display:none">
<h3>Step 3: Review & Submit</h3>
<p>Please review your information before submitting.</p>
<button type="button" class="prev-btn">Previous</button>
<button type="submit">Submit</button>
</div>
</form>
Importante: Use para botões de navegação para evitar a submissão acidental de formulários. Só o botão final “Submeter” deve ter .
CSS: Gerenciando Visibilidade e Estilhamento
Em vez de confiar em , é mais limpo usar classes CSS. Adicione o seguinte à sua folha de estilo:
.step {
display: none;
}
.step.active {
display: block;
}
Em seguida, no HTML, remova os atributos em linha e adicione apenas ao primeiro passo. O JavaScript irá alternar a classe para mostrar/esconder os passos.
Você também pode adicionar transições, barras de progresso e espaçamento consistente. Por exemplo:
.step {
opacity: 0;
transition: opacity 0.3s ease;
}
.step.active {
opacity: 1;
display: block;
}
Isso cria um efeito suave desbotamento ao mudar de passos.
JavaScript: Navegação e Validação
Agora vamos escrever a lógica central: movendo-se entre passos, validando os campos de cada passo e atualizando a interface.
Seleccionando Elementos DOM
const steps = document.querySelectorAll('.step');
const nextBtns = document.querySelectorAll('.next-btn');
const prevBtns = document.querySelectorAll('.prev-btn');
let currentStep = 0; // index of the currently visible step
Funções de Navegação
function showStep(stepIndex) {
steps.forEach((step, index) => {
step.classList.toggle('active', index === stepIndex);
});
currentStep = stepIndex;
}
function nextStep() {
if (validateStep(currentStep)) {
showStep(currentStep + 1);
}
}
function prevStep() {
showStep(currentStep - 1);
}
Validação por Passo
Escreva uma função que verifique todos os campos necessários na etapa atual e mostre mensagens de erro. Para simplificar, usaremos neste exemplo, mas um formulário de produção deve mostrar mensagens de erro inline próximas aos campos.
function validateStep(stepIndex) {
const currentStepDiv = steps[stepIndex];
const inputs = currentStepDiv.querySelectorAll('input[required]');
for (let input of inputs) {
if (!input.value.trim()) {
alert(`Please fill in "${input.placeholder || input.name}".`);
input.focus();
return false;
}
// Additional validation per type can be added here
if (input.type === 'email' && !isValidEmail(input.value)) {
alert('Please enter a valid email address.');
input.focus();
return false;
}
}
return true;
}
function isValidEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email.trim());
}
Anexar os Ouvintes de Eventos
nextBtns.forEach(btn => btn.addEventListener('click', nextStep));
prevBtns.forEach(btn => btn.addEventListener('click', prevStep));
Nota: Isto assume que cada passo tem exatamente um botão “Next” e um “Anterior”. Para formulários mais complexos, você pode querer usar atributos de dados (por exemplo, ]) para mapear botões para passos específicos.
Técnicas de Validação Avançada
Embora as verificações básicas de campo sejam essenciais, as formas modernas beneficiam de validação mais sofisticada que melhora a experiência do usuário e a qualidade dos dados.
Validação da Restrição HTML5
Os navegadores modernos suportam validação embutida para , , , , etc. Você pode alavancar o método e a pseudoclasse para o estilo.
function validateStepHTML5(stepIndex) {
const currentStepDiv = steps[stepIndex];
const inputs = currentStepDiv.querySelectorAll('input, select, textarea');
for (let input of inputs) {
if (!input.checkValidity()) {
input.reportValidity(); // shows the browser's native error tooltip
return false;
}
}
return true;
}
Validação em tempo real
Para dar aos usuários feedback imediato ao digitar, ouça ou eventos em campos individuais. Por exemplo:
const emailInput = document.getElementById('email');
emailInput.addEventListener('blur', function() {
if (this.value && !isValidEmail(this.value)) {
this.classList.add('invalid');
// show an error message next to the field
} else {
this.classList.remove('invalid');
}
});
Validação personalizada do Regex
Para campos como números de telefone, códigos postais ou senhas, use atributos ou regex personalizado. Exemplo para um número de telefone dos EUA (10 dígitos):
<input type="tel" id="phone" name="phone" pattern="\d{3}-\d{3}-\d{4}" placeholder="123-456-7890" />
Em seguida, no JavaScript, você pode verificar ou testar o valor com o seu próprio regex.
Adicionar um indicador de progresso
Uma barra de progresso ou contador de passos ajuda os usuários a entender quantos passos permanecem e reduz a ansiedade. Aqui está uma implementação simples usando JavaScript e CSS.
Estrutura HTML para os Passos de Progresso
<div id="progress">
<span class="progress-step active">1</span>
<span class="progress-step">2</span>
<span class="progress-step">3</span>
</div>
Styling CSS
.progress-step {
display: inline-block;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
border-radius: 50%;
background: #ccc;
color: #fff;
}
.progress-step.active {
background: #007bff;
}
Atualização do JavaScript
Dentro da função , também atualizar os indicadores de progresso:
function showStep(stepIndex) {
steps.forEach((step, index) => {
step.classList.toggle('active', index === stepIndex);
});
document.querySelectorAll('.progress-step').forEach((el, index) => {
el.classList.toggle('active', index === stepIndex);
});
currentStep = stepIndex;
}
Você também pode adicionar uma barra de progresso linear calculando a porcentagem: e definindo a largura de um ].
Manuseando casos de borda e detalhes da experiência do usuário
Para construir uma forma multi-passo pronta para a produção, considere estes aspectos adicionais:
Navegação do Teclado
Os usuários devem ser capazes de avançar com a tecla Enter (acionar o botão “Next”) e para trás com Escape[] ou um atalho dedicado. Certifique-se de que todos os botões e campos são focais e a ordem de tabulação é lógica.
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && e.target.closest('.step.active')) {
const nextBtn = document.querySelector('.step.active .next-btn');
if (nextBtn) nextBtn.click();
}
});
Prevenção de Múltiplas Submissões
Desactivar o botão de envio após o primeiro clique para evitar envios de formulários duplicados:
const submitBtn = document.querySelector('button[type="submit"]');
submitBtn.addEventListener('click', function() {
this.disabled = true;
this.textContent = 'Submitting…';
// The form will submit naturally after this
});
Armazenar Dados Temporariamente
Se o usuário atualizar acidentalmente a página, eles perdem todos os dados inseridos. Considere armazenar os valores do campo em ou à medida que o usuário progride. Na carga da página, restaure os valores e salte para o último passo salvo.
Considerações sobre segurança
A validação do lado do cliente é apenas para a experiência do usuário; valide e sanite sempre os dados no servidor. Use HTTPS e considere adicionar tokens CSRF para formulários sensíveis.
Acessibilidade (A11y) Melhores práticas
Os formulários multi-passos podem ser desafiadores para os utilizadores de leitura de ecrã, se não forem codificados correctamente.
- Usar e para agrupar cada passo logicamente.
- Anunciar mudanças de passos usando ]Regiões vivas da ARIA (por exemplo, ]) para que os leitores de tela saibam que novo conteúdo apareceu.
- Adicionar [[FLT: 45]] ao passo atual do progresso.
- Assegura que as mensagens de erro estão programáticamente associadas aos campos de entrada (use ).
- Certifique-se de que todos os elementos interativos são acessíveis ao teclado e têm indicadores de foco visíveis.
<div class="step active" id="step1" aria-live="polite">
<h3>Step 1 of 3: Personal Information</h3>
<label for="name">Full Name</label>
<input type="text" id="name" name="name" required />
<span id="name-error" class="error" role="alert"></span>
</div>
Quando a validação falhar, insira a mensagem de erro no e será anunciada.
Juntando tudo: Um exemplo completo
Abaixo está uma versão condensada de um formulário multi-passo totalmente funcional com validação e um indicador de progresso. Você pode adaptar esta estrutura aos seus próprios projetos.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Multi‑Step Form with Validation</title>
<style>
.step { display: none; }
.step.active { display: block; }
.progress-step { background: #ccc; padding: 5px 10px; margin: 0 2px; }
.progress-step.active { background: #007bff; color: #fff; }
.error { color: red; font-size: 0.9em; }
</style>
</head>
<body>
<form id="multiStepForm" novalidate>
<div id="progress">
<span class="progress-step active">1</span>
<span class="progress-step">2</span>
<span class="progress-step">3</span>
</div>
<div class="step active" id="step1">
<h3>Step 1: Personal Information</h3>
<label for="name">Full Name *</label>
<input type="text" id="name" name="name" required minlength="2">
<button type="button" class="next-btn">Next</button>
</div>
<div class="step" id="step2">
<h3>Step 2: Contact Details</h3>
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
<button type="button" class="prev-btn">Previous</button>
<button type="button" class="next-btn">Next</button>
</div>
<div class="step" id="step3">
<h3>Step 3: Submit</h3>
<p>Review your details and submit.</p>
<button type="button" class="prev-btn">Previous</button>
<button type="submit">Submit</button>
</div>
</form>
<script>
const steps = document.querySelectorAll('.step');
const nextBtns = document.querySelectorAll('.next-btn');
const prevBtns = document.querySelectorAll('.prev-btn');
const progressSteps = document.querySelectorAll('.progress-step');
let currentStep = 0;
function showStep(index) {
steps.forEach((step, i) => step.classList.toggle('active', i === index));
progressSteps.forEach((step, i) => step.classList.toggle('active', i === index));
currentStep = index;
}
function validateCurrentStep() {
const stepDiv = steps[currentStep];
const inputs = stepDiv.querySelectorAll('input[required]');
for (let input of inputs) {
if (!input.checkValidity()) {
input.reportValidity();
return false;
}
}
return true;
}
nextBtns.forEach(btn => {
btn.addEventListener('click', function(e) {
if (validateCurrentStep()) {
showStep(currentStep + 1);
}
});
});
prevBtns.forEach(btn => {
btn.addEventListener('click', function(e) {
showStep(currentStep - 1);
});
});
// Optional: handle Enter key
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && e.target.closest('.step.active')) {
const nextBtn = document.querySelector('.step.active .next-btn');
if (nextBtn) nextBtn.click();
}
});
</script>
</body>
</html>
Este exemplo usa a validação HTML5 (]) e as mensagens de erro incorporadas. Você pode substituir por formatação de erro personalizada, se necessário.
Leitura e recursos adicionais
Para aprofundar sua compreensão sobre validação de formulários e acessibilidade, verifique estes recursos:
- MDN: Validação de Formulários do Cliente-Side
- WAI Web Accessibility Tutoriais: Formulários multi-páginas
- MDN: Regiões ARIA Vivas
- Directus Blog: Construindo formulários melhores[ (para ideias de integração de backend)
A Completar
Formas multi-step construídas com JavaScript são uma ferramenta poderosa para melhorar a experiência do usuário e precisão de dados. Ao quebrar um formulário longo em seções gerenciáveis, validar a entrada em cada etapa, e fornecer pistas de progresso visual, você pode reduzir drasticamente o abandono de formulários e coletar dados mais limpos.
Comece com uma estrutura HTML sólida, camada em CSS para feedback visual e, em seguida, adicione JavaScript para navegação e validação. Expanda seu formulário com validação em tempo real, indicadores de progresso e recursos de acessibilidade para torná-lo utilizável para todos. Finalmente, lembre-se sempre que a validação do lado do cliente é uma conveniência – nunca confie nele sozinho. Valide todos os dados no servidor também.
Experimente diferentes projetos e técnicas de validação para atender às necessidades da sua aplicação. As técnicas mostradas aqui fornecem uma base que você pode adaptar e estender para qualquer projeto de formulário multi-passo.