Skip to main content

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! 🙌




33%20PM


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/



  1. Create form in one column the way you normally would, in the order you want the fields to appear.

  2. 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>


  1. 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>


  1. 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>



  1. 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)




  2. 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.




  3. 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



notworthy

After adding the code to fix the back button I have a really big problem editing the css so that buttons look good, have backgrounds, etc.

Any chance anyone can help me with this. Thanks.


Has anyone discovered how to get the progress bar to function properly? Currently it displays all three steps/titles at the same time and we haven’t been able to find a working fix.


Does anyone know how to customise the button names between the different steps? At the moment the text for my next button and submit button are the same. I would like these to be different. So the final submit button can naturally be called submit but the button on the first step can be something like “tell us more” or whatever. Thanks for the inputs.


Chris


Hey Fourward,


In the second script, where you set how many fields to show per step you should see a line “nextButton”. If you change this that should change the text for your next button, for example, you can change it from ‘Continue »’ to ‘tell us more’. For your submit button, just change the text of the button connected to the form in the Unbounce editor.


Why hasn’t unbounce made this a feature that can be easily implemented for those of us who don’t know how to code? I’m trying to get this to work properly but I’m completely lost, and the more I look into things as someone who doesn’t code, it seems like it would just be easier to use a wordpress template for a landing page and then use one of the many plugins to make a multistep form easily.


So awesome! Thank you very much.


For some reason, this isn’t working for me. I’ve followed all the steps exactly, but my form won’t sync with my Script. I’ve tried even changing button labels, no luck. My form was previously setup using the original code. Do I need to delete my form and start from scratch?


Hi! how do i get the progress bar to show up with the names in the actual field? i’m not seeing this step in the CSS section?



Seems like a dead link, any chance to fix it or put a link to a working example so we can see how it should look like since sometimes it doesn’t do what we expect? Thanks


Hi all, I’ve been using the multi step form for a while now (love love love it!), however, we recently added a field to collect phone numbers for an SMS reminder. It’s an optional field, but is set to validate the phone number. Problem is, error messages are displaying in a dumb spot.



I tried adding the scripts from oHow to] Add Inline Form Error Messages, but it doesn’t seem to work. I tried adjusting the location in the CSS field, but I suspect this script is older and I’m guessing the display of errors has changed since then.


Has anyone solved this problem? @Caroline


You can view my test at https://get.mintcro.com/wlp9fb/d.html


If I can solve this, I think I might improve our optin rate 🙂


Thanks in advance!

Kirsti


Hi Filip!


Here is a test page where you can see the multi-step form in action! 🙂


http://unbouncepages.com/multi-field-multi-step-form/







buttonissue


Ugh
 I’ve figured everything else out, got my multi-step form looking EXCELLENT. THANK YOU GUYS SO MUCH FOR THE INPUT!


Only one major issue
 I cannot for the life of me get the “Submit” or as I’ve labeled it “Get My Estimate” button to center the text vertically without doing a line-height of 1px. However, when I do that, it bunches up what would be two lines of text in my mobile version.


How can I either


a) fix the line height and vertical centering issue or

b) auto adjust button width to fit text on mobile?


#next-button, #back-button {
display: block;
border-style: none;
border-radius: 5px;
left: 0;
height:49px;
line-height:1px;
position: absolute;
background: rgba(0,186,242,1);
color: #fff;
font-size: 16px;
font-family: arial;
font-style: normal;
text-align: center;
}

I was wondering to know how do i can enable the progress bar. Some one can help me with that?


Try this : [How To] Add A Multi-Step Form 2.0


Totally agree!


Great script! This is sure to boost conversions!


I am having some problems with the layout on the final step of the form. The form is changing from single column to multi-column and everything is overlapping!


Does anybody know what I’m doing wrong, or how to fix this problem?


http://unbouncepages.com/multistep-form-testing12032020/


Hi @thundr! Welcome to the community 🎉


Great job so far on the form! Would you mind sharing the code you’re using for us to take a peak? It will help us to troubleshoot the problem. 🙂


-Jess


Hi @Jess,


CSS:



<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: 1px !important;
font-weight: 700 !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: 1px !important;
font-weight: 700 !important;

}

.multistep.initial .lp-pom-button.back-button {
display: none !important;
}

.lp-pom-form .lp-pom-form-field .text {
font-family: 'Arial' !important;
font-weight: 700 !important;

color: #3f4144 !important;
font-size: 14px !important;
letter-spacing: 1px !important;
}

.lp-pom-form .lp-pom-form-field select {
background-color: #ffffff !important;
border-radius: 5px;
font-family: 'Arial' !important;
font-weight: 700 !important;

color: #3f4144 !important;
font-size: 14px !important;
letter-spacing: 1px !important;
}
</style>


JS 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 = [];
this.currentStep = 0;
this.forwardButton = this.form.find('button[type=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.steps[currentStep].title +
'</span>' +
'</div>'
);
this.fieldsByStep[currentStep] = [];
for (i = 0; i < this.options.steps[currentStep].fields; i++) {
console.log('Field ' + currentField + ' -> step ' + currentStep);
this.fields.eq(currentField).appendTo(this.steps.eq(currentStep));
this.fieldsByStep[currentStep].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.fieldsByStep[currentStep].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)[0].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>


JS Multi Step 2:


<script>
jQuery('.lp-pom-form form').unbounceMultiStep({
steps: [
{ title: '', fields: 4 },
{ title: '', fields: 2 },
{ title: '', fields: 3 },



],
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');

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;"> By submitting your details you agree to our terms and conditions and privacy policy.</p>';

jQuery('fieldset.step:last-of-type').append(disclaimer);

jQuery(window).keydown(function(event) {
if (event.keyCode === 13) {
event.preventDefault();
return false;
}
});
</script>

Thanks!


I’m having the same issue! @Jess


Hello

i follow the instruction but its not working. Is it possible that if you upload a video it help alot

thanks


Try adjusting the CSS script



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’);



Change the PX to 340px+


I need help .Process bar funcrion is avalible in code but not show process bar


this.progressBarItems = jQuery(’#progress-bar .step’);


I’ve seen a few people post about going to the next step of the form once a radio button has been selected for instance? Is there any way of having an event listener attached to the active question that then calls the goToStep method to go to the next step? And a follow up on that would be making the next button only appear if it isn’t a single question radio button step in the form. If anyone has any advice it would be greatly appreciated, trying to hack away at it.


Hey @DKSander,


Generally speaking the answer to your question is - yes.


The provided script here is a great resource for those that need a quick and easy way to implement a multi-step form but as with most things it has its limitation. There is simply no way to account for all edge cases and considerations with a single script.


My agency has done a lot of multi-step scripts for clients on Unbounce over the years and based on experience, I can tell you it can get pretty complicated pretty fast.


Here is one fully custom Unbounce form that seems easy and straightforward on the surface but it’s actually 300 lines of JS and about 500-600 lines of CSS.



Best,

Hristian


Thank for your shares a lot of. I look forward to the interesting thing in the future about u.


Reply