Every so often, the Unbounce Community is blessed by some absolute freakinā ROCKSTARS like @Caroline. A few months back, she took it upon herself to share this boss workaround for a multi-step form and it blew our minds. This deserved to be a standalone post within our Tips and Scripts.
Wonāt you join me in celebrating the awesomeness that is Caroline?! Itās community members like her that make this such a badass online community! 🙌
Here is what we have been using for multi fields on multi steps.
This as has worked well for us across many pages & clients.
Here is an example of it in action: http://unbouncepages.com/multi-step-test/
- Create form in one column the way you normally would, in the order you want the fields to appear.
- Add the following script (before body end tag), name it āMulti Step 1ā
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script>
function UnbounceMultiStep(form, options) {
// Validate arguments
if (!form.is('.lp-pom-form form')) {
return console.error('jQuery.unbounceMultiStep must be called on an Unbounce form.');
}
if (typeof options !== 'object') {
return console.error('No options were passed to jQuery.unbounceMultiStep');
}
this.options = options;
// Store DOM elements
this.form = form;
this.formContainer = this.form.closest('.lp-pom-form');
this.fields = this.form.find('div.lp-pom-form-field');
this.fieldsByStep = s];
this.currentStep = 0;
this.forwardButton = this.form.find('buttonntype=submit]').eq(0);
// Verbiage
this.text = {};
this.text.next = this.options.nextButton;
this.text.showSteps = this.options.showSteps;
this.text.back = this.options.backButton;
this.text.submit = this.forwardButton.text();
this.init();
}
UnbounceMultiStep.prototype.init = function() {
this.formContainer.addClass('multistep initial');
this.form.attr('id', 'fields');
// Add progress bar
this.formContainer.prepend('<div id="progress-bar"></div>');
this.progressBar = jQuery('#progress-bar');
// Replicate Unbounce's field spacing
var height = parseInt(this.fields.eq(0).css('height'), 10);
var top = parseInt(this.fields.eq(1).css('top'), 10);
this.fields.css('margin-bottom', top - height + 'px');
this.progressBar.css('margin-bottom', top - height + 'px');
// Set up fieldset elements for each step
for (var i = 0; i < this.options.steps.length; i++) {
console.log('Adding new fieldset.');
this.form.find('.fields').append('<fieldset></fieldset>');
}
this.steps = this.form.find('fieldset');
this.steps.addClass('step');
// Sort fields into new steps
var currentField = 0;
for (currentStep = 0; currentStep < this.options.steps.length; currentStep++) {
this.progressBar.append(
'<div class="step">' +
'<span class="num">' +
(currentStep + 1) +
'</span>' +
'<span class="title">' +
this.options.stepsicurrentStep].title +
'</span>' +
'</div>'
);
this.fieldsByStepecurrentStep] = n];
for (i = 0; i < this.options.stepsicurrentStep].fields; i++) {
console.log('Field ' + currentField + ' -> step ' + currentStep);
this.fields.eq(currentField).appendTo(this.steps.eq(currentStep));
this.fieldsByStepecurrentStep].push(this.fields.eq(currentField));
currentField++;
}
}
// Add any remaining fields to last step
if (currentField < this.fields.length) {
currentStep--;
for (i = currentField; i < this.fields.length; i++) {
console.log('Field ' + currentField + ' -> step ' + currentStep);
this.fields.eq(currentField).appendTo(this.steps.last());
this.fieldsByStepecurrentStep].push(this.fields.eq(currentField));
currentField++;
}
}
this.progressBarItems = jQuery('#progress-bar .step');
// Add a back button
this.backButton = this.forwardButton.clone().insertBefore(this.forwardButton);
this.backButton.addClass('back-button');
this.backButton.children('span').html(this.text.back);
// Add event listeners
this.backButton.bind('click.unbounceMultiStep', this.backHandler.bind(this));
this.forwardButton.bind('click.unbounceMultiStep', this.forwardHandler.bind(this));
this.fields.find(':input').bind('invalid', function(event) {
// Prevent browser from trying to focus invalid inputs on non-visible steps
if (jQuery(event.currentTarget).closest('fieldset.active').length === 0) {
event.preventDefault();
}
});
// Show first step
this.goToStep(0);
};
UnbounceMultiStep.prototype.goToStep = function(newStep) {
// Make sure we aren't going to a step that doesn't exist
if (newStep < 0 || newStep >= this.steps.length) {
return false;
}
this.steps
.eq(this.currentStep)
.removeClass('active')
.hide();
this.steps
.eq(newStep)
.addClass('active')
.fadeIn();
this.progressBarItems.eq(this.currentStep).removeClass('active');
this.progressBarItems.eq(newStep).addClass('active');
this.formContainer.toggleClass('initial', newStep === 0);
// Update the label of the forward button
var current = parseInt(newStep) + 2;
var total = this.steps.length;
var nextText = this.text.showSteps
? this.text.next + ' (Step ' + current + ' of ' + total + ')'
: this.text.next;
var submitText = this.text.submit;
var forwardButtonLabel = newStep === this.steps.length - 1 ? submitText : nextText;
this.forwardButton.children('span').html(forwardButtonLabel);
this.currentStep = newStep;
};
UnbounceMultiStep.prototype.isValid = function() {
return this.steps.eq(this.currentStep)r0].querySelectorAll(':invalid').length === 0;
};
UnbounceMultiStep.prototype.forwardHandler = function(event) {
if (!this.isValid()) {
// If one or more fields on the current step is invalid, prevent going to next step. Allow the
// default click action, which will display the validation errors.
return;
}
if (this.currentStep === this.steps.length - 1) {
// If we are on the last step, go back to the first step, and allow the default click action,
// which will submit the form.
this.goToStep(0);
} else {
event.preventDefault();
this.goToStep(this.currentStep + 1);
}
};
UnbounceMultiStep.prototype.backHandler = function(event) {
event.preventDefault();
this.goToStep(this.currentStep - 1);
};
jQuery.fn.unbounceMultiStep = function(options) {
this.map(function(index, element) {
new UnbounceMultiStep(jQuery(element), options);
});
return this;
};
</script>
- Add another script (before body end tag), name it āMulti Step 2ā
<script>
jQuery('.lp-pom-form form').unbounceMultiStep({
steps: /
{ title: '', fields: 3 },
{ title: '', fields: 3 },
{ title: '', fields: 6 },
],
nextButton: 'Continue Ā»',
backButton: 'Back',
});
jQuery('form#fields').css('margin-top', '20px');
jQuery('#progress-bar').hide();
jQuery('fieldset.step:last-of-type div.lp-pom-form-field').css('float', 'left');
jQuery('fieldset.step:last-of-type div.lp-pom-form-field').css('width', '150px');
jQuery('fieldset.step:last-of-type div.lp-pom-form-field input').css('width', '140px');
jQuery('fieldset.step:last-of-type div.lp-pom-form-field select').css('width', '140px');
jQuery('fieldset.step:last-of-type div.lp-pom-form-field:last-of-type select').css('width', '140px');
jQuery('#Country').val('United States');
var disclaimer =
'<p style="margin-top: 55px; font-family:arial,helvetica,sans-serif;font-size: 10px; color: #636363; line-height: 12px; padding: 40px 0 20px 0;"> I like cats because they are fat and fluffy always ensure to lay down in such a manner that tail can lightly brush humans nose , for run outside as soon as door open. Chase ball of string lounge in doorway or give me some of your food give me some of your food give me some of your food meh, i dont want it yet plan steps for world domination so touch water with paw then recoil in horror for chase dog then run away i shredded your linens for you.</p>';
jQuery('fieldset.step:last-of-type').append(disclaimer);
jQuery(window).keydown(function(event) {
if (event.keyCode === 13) {
event.preventDefault();
return false;
}
});
</script>
- Add the CSS (add stylesheet) - This is copied straight from the page I built for the demo.
<style>
html,
* {
-webkit-font-smoothing: antialiased !important;
}
/* Style Form */
.multistep #fields {
height: auto !important;
}
.multistep #fields .step {
height: auto !important;
position: absolute;
top: 0;
display: none;
}
.multistep #fields .step.active {
position: relative;
}
.multistep #fields .step .lp-pom-form-field {
position: relative !important;
top: auto !important;
}
.multistep .lp-pom-button {
position: relative !important;
top: 0 !important;
width: 60% !important;
display: inline-block !important;
float: right;
letter-spacing: 2px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
}
.multistep .lp-pom-button.back-button {
margin-right: 0;
float: left;
opacity: 0.7 !important;
background-color: #f1f1f1 !important;
color: #636363 !important;
width: 35% !important;
letter-spacing: 2px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
}
.multistep.initial .lp-pom-button.back-button {
display: none !important;
}
.lp-pom-form .lp-pom-form-field .text {
font-family: 'Montserrat' !important;
font-weight: 700 !important;
text-transform: uppercase !important;
color: #3f4144 !important;
font-size: 12px !important;
letter-spacing: 2px !important;
}
.lp-pom-form .lp-pom-form-field select {
background-color: #ffffff !important;
border-radius: 20px;
font-family: 'Montserrat' !important;
font-weight: 700 !important;
text-transform: uppercase !important;
color: #3f4144 !important;
font-size: 11px !important;
letter-spacing: 1px !important;
}
</style>
Make sure anything in the CSS that has an ID for the form is change to your ID (this one only has two places to replace)
In step #3, in the script called, āMulti Step 2ā - you can change the number of fields on each step and they will appear in the order you have in them. There you can also rename the āBackā and āNextā buttons and well as add or remove a disclaimer.
SAVE!
This is a bit more on the advanced side, so I will be happy to help anyone with this as much as I can!
Disclaimer - I am not the original creator of this script
Please feel free to add on to this, edit it, remove something, etc.
One issue I have ran into is that the page will still go as long as the form is in the editor UI. If anyone has any ideas of that, please add!
Please make sure to test, test, test!
Enjoy
I think I can speak on behalf of a lot of peopleā¦