Solved

Multi-Field, Multi-Step Form 🔥


Userlevel 7
Badge +1
  • Former Community Manager @ Unbounce
  • 831 replies

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 = [];
    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>
  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

icon

Best answer by TimothyDO 7 August 2018, 15:27

View original

100 replies

Userlevel 7
Badge +4

This is an epic script. So useful! We’re going to give it a try right away and see what we come up with. Thank you for sharing it!

Userlevel 5
Badge +2

Thank you, @Nicholas! I look forward to seeing any advances on this! #sharingiscaring

Awesome @Caroline a real game changer for conversion freaks like me. Thanks!

Amazing @Caroline ! Thank you so much for sharing. Can’t wait to test this out.

This is truly an amazing script (knowing how difficult is to workaround Unbounce’s inflexible structure) Caroline, big thanks for sharing it!

I’m experiencing very odd issue though where I’ve added the email field to the last step (there are 4 steps), set it to required, included email formatting and now when I try to get past the first step, I get a form warning that email field needs to be entered, even though it’s hidden in step 4. Spent few hours troubleshooting this issue with Chrome console and defining custom rules and I can’t seem to find what’s causing this as phone number validation with formatting enabled works just fine. Very odd. If I make the email field (on the last step) not required, the issue does not persist, however, I need to have it formatted and mandatory.

I’ve seen one person on the other post where you’ve shared the script initially had an issue similar to this, you’ve answered him in private, maybe you know what the issue was? Thanks again for the script!

Userlevel 5
Badge +2

Hi @Edvinas_Puskorius -

Yes, this is an issue I have been working on for a bit now! I’ve been getting closer, but still haven’t completed it. Hopefully someone else in this community has figured it out and can share!

Really hope so, will continue looking for solution myself.

Hoping someone could help me with this.

I’m trying to figure out how to make the box that I place the form in responsive.

So when you go from step 1, where I only display 1 question.
To step 4, where I display my question + a TOS & Privacy agreement.
I’d like the box that I place this form in to be responsive depending on where the submit button moves too.

How can I do this with code?

Userlevel 5
Badge +2

Hi @Wayne_White!

I believe this idea has been thrown around quite a few times on many different posts! Unfortunately I have not seen anyone post a solution. Perhaps a work-around could be shortening your TOS & Privacy statement to a link to the full statement so the last step isn’t much longer than the other steps?

Hi @Caroline,

Thank you for the script! We successfully implemented it but on mobile I am no longer able to use the “go” button in the keypad to submit any part of the form. Do you know of a way to allow this functionality? I was testing on an android smartphone. Thanks again!

Hey

Is there a way to have the “next step” buttons and the “submit” button have different ID-s? That way, we could event track what step they left the form, retarget people who submitted first step but have not finished the form, etc.

@Caroline thank you sooooooo much for this tutorial, this will definitely increase conversion for a long form.
I’m having trouble with that looks like the 2 extra sections on the bottom, the red section and the image with the YUM text.
How do I get rid of those? I can’t find them in the code and I just need the form.

Thank you!!

Userlevel 5
Badge +2

Hi @raget!

Those are just sections on the page I created - the code will not contain those elements!

Has anyone been able to solve this email required issue? I’m running into the same thing. Thanks!

Userlevel 5
Badge +2

Hi @ibrudap! I will take a look at this for you! Be on the lookout for a message from me shortly 🙂

Thanks for the code! I’m running into one issue where the button is on top of the form (I’ve included screengrab below) thanks again for your help!

23%20AM

Userlevel 5
Badge +2

Hi @gunderw1 !

Go into the CSS for this and edit the top property for the lp-pom-button:

	.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;
		}

Increase 0 to a unit of your liking (probably around 20 should do it). Please feel free to PM me if you have additional questions or issues!

Hey guys,

I’ve been working a lot with this Multi-Step Form to make it work. Already solved many issues, but I have a main one that would like to ask if anyone else has the same.

First:
If someone presses enter instead of clicking the Button manually to go to the second step of the form, the form jumps automatically to the redirection without completing the form.
Is there a way to set up the “Enter” option for the next button instead of the Final SEND one?

Second:
After completing the form, when you press the last “SEND” button, the form jumps again to step one before redirecting to the Thank you page. Why does this happen?
Can someone please help me figuring out this?

Is this happening to others too? If I solve it, I would definitely share it with you.

Thanks in advance!

(HERE is the page I’m working on. Feel free t do a Test to understand the issue)

Also having this issue, looking into it but if anyone gets there first… PLEASE share 😉

Okay think I got the email validation issue… might also need a little extra for phone validation but the page I am working on doesn’t require a phone number so will update if and when I find I need phone validation.

Fix is as follows… just need a little extra in the validation skipping for different pages 😃

// Only validate fields that are in current step

  $.each(window.module.lp.form.data.validationRules, function() {
    if ( this.email === true ) {
      this.email = $(this).is('.active :input');
      this.required = {
      	depends: function () {
          return $(this).is('.active :input');
      	}
      };
	}
    else if ( this.required === true ) {
      this.required = {
      	depends: function () {
          return $(this).is('.active :input');
      	}
      };
	}
  });
Userlevel 5
Badge +2

@TimothyDO - Great work & thank you for sharing! Myself and many others thank you!

Okay so next challenge,

Anyone else tried custom validation with this script?

I’ve just tried implementing the data8 custom validation from https://blog.data-8.co.uk/2018/01/25/validating-email-telephone-numbers-in-unbounce-forms/

((Code actually looks like this… formatting on the blog post screws up the code formating))

<script type="text/javascript">window.jQuery = lp.jQuery;</script>
<script type="text/javascript" src="https://webservices.data-8.co.uk/javascript/loader.ashx?key=API_KEY_HERE&load=InternationalTelephoneValidation,EmailValidation"></script>
<script type="text/javascript" src="https://webservices.data-8.co.uk/javascript/jqueryvalidation_min.js"></script>
<script type="text/javascript">
window.module.lp.form.data.validationRules.telephone.d8val_inttelephone = true;
window.jQuery(document).ready(function() { 
	window.module.lp.form.data.validationMessages.telephone.d8val_inttelephone = "Data8: Invalid telephone number";
}); 
</script>

It does seem to work on occasion but will never work on the first click of the next button…
Anyone got any thoughts?

I’m also having this issue. Have you had any luck yet? @Caroline is this something you’ve looked into or have a fix for? After I submit the form, the form returns to step 1 while the form is being submitted and a URL redirect takes place to a thank you page.

 if ( this.currentStep === this.steps.length - 1 ) {
    this.form.submit();
    this.goToStep(0);
}

If you look for this section, this is what both submits the form and jumps the page back to step one on submission. You can happily delete the this.goToStep(0); section that will stop the jump back to the first page.
As the what happens on the submission of the form that is controlled from the unbounce editor as this is just calling the standard submission with the this.form.submit();

Hi @Caroline, I’m now having a similar problem as @ibrudap.
Can’t seem to get the “next” and “back” button to align with the form.

Here is the example, it’s in spanish:
http://unbouncepages.com/entrenamiento/argentina/

Thanks!

Reply