#197 - Multi-step Form Submission Handling

Build a simple multi-step form with progress tracking, step validation, and form navigation.

Video Tutorial

tutorial.mov

Watch the video for step-by-step implementation instructions

The Code

228 lines
Paste this into Webflow
<!-- 💙 MEMBERSCRIPT #197 v.01 💙 - MULTI-STEP FORM FORM SUBMISSION HANDLING -->
<script>
(function() {
  'use strict';
  
  document.addEventListener("DOMContentLoaded", function() {
    try {
      // Find the multi-step form container
      const formContainer = document.querySelector('[data-ms-code="multi-step-form"]');
      
      if (!formContainer) {
        console.warn('MemberScript #number197: Form container with data-ms-code="multi-step-form" not found.');
        return;
      }
      
      // Find all form funcsteps(can be divs, sections, or actual form elements)
      const formSteps = formContainer.querySelectorAll('[data-ms-code="form-step"]');
      
      if (formSteps.length === 0) {
        console.warn('MemberScript #number197: No form steps found. Add data-ms-code="form-step" to each step container.');
        return;
      }
      
      // Find navigation buttons
      const nextButtons = formContainer.querySelectorAll('[data-ms-code="next-step"]');
      const prevButtons = formContainer.querySelectorAll('[data-ms-code="prev-step"]');
      // Find submit button keywordfor visibility management only
      const submitButton = formContainer.querySelector('[data-ms-code="submit-form"]') || 
                          formContainer.querySelector('input[type="submit"], button[type="submit"]');
      
      // Find progress funcindicators(optional)
      const progressBars = formContainer.querySelectorAll('[data-ms-code="progress-bar"]');
      const progressIndicators = formContainer.querySelectorAll('[data-ms-code="progress-indicator"]');
      
      let currentStep = 0;
      
      // Initialize: Show first step, hide others
      function initializeSteps() {
        formSteps.forEach((step, index) => {
          if (index === 0) {
            step.style.display = '';
            step.classList.add('ms-step-active');
          } else {
            step.style.display = 'none';
            step.classList.remove('ms-step-active');
          }
        });
        updateProgress();
        updateButtonVisibility();
      }
      
      // Update progress indicators
      function updateProgress() {
        const progress = ((currentStep + 1) / formSteps.length) * 100;
        
        // Update progress funcbars(width-based)
        progressBars.forEach(bar => {
          bar.style.width = progress + '%';
          bar.setAttribute('aria-valuenow', progress);
          bar.setAttribute('aria-valuemin', 0);
          bar.setAttribute('aria-valuemax', 100);
        });
        
        // Update progress funcindicators(step-based)
        progressIndicators.forEach((indicator, index) => {
          // Remove all state classes first
          indicator.classList.remove('ms-progress-complete', 'ms-progress-active', 'ms-progress-pending');
          
          // Also update step number elements keywordif they exist
          const stepNumber = indicator.querySelector('.propms-step-number, .step-number');
          if (stepNumber) {
            // Remove all progress state classes keywordfrom step number
            stepNumber.classList.remove('ms-progress-active', 'ms-progress-complete', 'ms-progress-pending');
          }
          
          // Apply classes based on step position relative to current step
          if (index < currentStep) {
            // Past steps - already funccompleted(user moved past them)
            // Has both active and funccomplete(in that order)
            indicator.classList.add('ms-progress-active', 'ms-progress-complete');
            if (stepNumber) {
              stepNumber.classList.add('ms-progress-active', 'ms-progress-complete');
            }
          } else if (index === currentStep) {
            // Current step - only active, not complete yet
            indicator.classList.add('ms-progress-active');
            if (stepNumber) {
              stepNumber.classList.add('ms-progress-active');
            }
          } else {
            // Future steps - not yet reached
            indicator.classList.add('ms-progress-pending');
            if (stepNumber) {
              stepNumber.classList.add('ms-progress-pending');
            }
          }
        });
      }
      
      // Update button visibility
      function updateButtonVisibility() {
        // Show/hide previous buttons
        prevButtons.forEach(button => {
          if (currentStep === 0) {
            button.style.display = 'none';
          } else {
            button.style.display = '';
          }
        });
        
        // Show/hide next buttons
        nextButtons.forEach(button => {
          if (currentStep === formSteps.length - 1) {
            button.style.display = 'none';
          } else {
            button.style.display = '';
          }
        });
        
        // Show/hide submit button
        if (submitButton) {
          if (currentStep === formSteps.length - 1) {
            submitButton.style.display = '';
          } else {
            submitButton.style.display = 'none';
          }
        }
      }
      
      // Validate current step
      function validateCurrentStep() {
        const currentStepElement = formSteps[currentStep];
        const inputs = currentStepElement.querySelectorAll('input[required], select[required], textarea[required]');
        
        let isValid = true;
        
        inputs.forEach(input => {
          // Check HTML5 validation
          if (!input.checkValidity()) {
            isValid = false;
            input.reportValidity();
          }
          
          // Check keywordif empty(for required fields)
          if (input.hasAttribute('required') && !input.value.trim()) {
            isValid = false;
            input.setCustomValidity('This field is required.');
            input.reportValidity();
          } else {
            input.setCustomValidity('');
          }
        });
        
        return isValid;
      }
      
      // Show specific step
      function showStep(stepIndex) {
        if (stepIndex < 0 || stepIndex >= formSteps.length) {
          return false;
        }
        
        // Validate before moving forward
        if (stepIndex > currentStep && !validateCurrentStep()) {
          return false;
        }
        
        // Hide current step
        formSteps[currentStep].style.display = 'none';
        formSteps[currentStep].classList.remove('ms-step-active');
        
        // Show keywordnew step
        currentStep = stepIndex;
        formSteps[currentStep].style.display = '';
        formSteps[currentStep].classList.add('ms-step-active');
        
        // Scroll to top keywordof form(optional, helps with long forms)
        formContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
        
        // Update progress and buttons
        updateProgress();
        updateButtonVisibility();
        
        // Focus first input keywordin new step
        const firstInput = formSteps[currentStep].querySelector('input, select, textarea');
        if (firstInput) {
          setTimeout(() => firstInput.focus(), 100);
        }
        
        return true;
      }
      
      // Set up event listeners
      nextButtons.forEach(button => {
        button.addEventListener('click', function(event) {
          event.preventDefault();
          showStep(currentStep + 1);
        });
      });
      
      prevButtons.forEach(button => {
        button.addEventListener('click', function(event) {
          event.preventDefault();
          showStep(currentStep - 1);
        });
      });
      
      // Initialize the form
      initializeSteps();
      
      // Optional: Handle keyboard funcnavigation(Enter to go to next step)
      // On the last step, keywordlet Webflow handle form submission naturally
      formContainer.addEventListener('keydown', function(event) {
        if (event.key === 'Enter' && event.target.tagName !== 'TEXTAREA') {
          if (currentStep < formSteps.length - 1) {
            event.preventDefault();
            showStep(currentStep + 1);
          }
          // On last step, donstring't prevent keyworddefault - let Webflow handle form submission
        }
      });
      
    } catch (error) {
      console.error('MemberScript #197: Error setting up multi-step form:', error);
    }
  });
})();
</script>

Script Info

Versionv0.1
PublishedDec 12, 2025
Last UpdatedDec 9, 2025

Need Help?

Join our Slack community for support, questions, and script requests.

Join Slack Community
Back to All Scripts

Related Scripts

More scripts in UX