v0.1

UX
#95 - Confeti al clic
隆Haz volar un divertido confeti al hacer clic!
Watch the video for step-by-step implementation instructions
<!-- 馃挋 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, don string't prevent keyworddefault - let Webflow handle form submission
}
});
} catch (error) {
console.error('MemberScript #197: Error setting up multi-step form:', error);
}
});
})();
</script>More scripts in UX