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

Does anyone know how to embed this form feature?

Hey @ygivechi, the duedil form seems to just be a validated email on the first page and 5 additional fields on the next. If that’s all you’re looking for, the script on this thread should be OK for you with no modifications - what were you looking to do?

Hey! Thanks for replying!

So I currently have a CTA button which navigates to a lightbox with 3 multi-step form boxes.

I essentially wanted to capture the email first or another form question then lead to the Lightbox with the rest of the questions. Im not sure how to manipulate the script to separate an email from the rest of the unbounce form.

Ah I see. I think this is probably outside the scope of the (easily modified) script.

One way you could achieve a similar result would be to have one landing page to capture the email, then submit this to a second page that contains the rest of the questions (either where the form is in a lightbox coded to show on entry, or simply something that “looks like” a lightbox).

You can use configure a hidden email field on page 2 to be prepopulated with the value from step 1 - that way you capture all the emails on page 1, but also have them on page 2.

Hope that makes sense, I wrote this on my phone!

Userlevel 3
Badge +1

Hey, we had some issues on mobile devices because the fields were too wide so we added a quick fix to make the width different on mobile devices. Take a look:

First we create a variable fieldWidth

  var fieldWidth = '400px'; //Default width value for desktop
  
  if ($(window).width() < 600) {
   fieldWidth = '280px'; //Special width for mobile devices
}

Now replace the fixed width the new variable like this:

  jQuery('fieldset.step:last-of-type div.lp-pom-form-field').css('width', fieldWidth);

  jQuery('fieldset.step:last-of-type div.lp-pom-form-field input').css('width', fieldWidth);

  jQuery('fieldset.step:last-of-type div.lp-pom-form-field select').css('width', fieldWidth);

  jQuery('fieldset.step:last-of-type div.lp-pom-form-field:last-of-type select').css('width', fieldWidth);

I hope this helped! 🙂

@happyagencies Out of curiosity, can you not just change the form width in mobile mode within the Unbounce editor?

Userlevel 3
Badge +1

Not with that code because it was overwritting it with inline css.

Fair enough… our multistep script although based on this has diverged significantly from it 🙂

Hello!
I’m having an issue with the form: when I try to put 2 fields on the last step they are not put one above the other but next. Is there a way to easily solve this? Here how it looks:

I’d really love to have these 2 together as the second one really doesnt’t make much sense on its own but it’s mandatory.
Thank you!

@s.bacci, drop us a link to your landing page, should be able to send you some CSS!

Here it is! 😉
LP Multistep test

Hey @s.bacci,

Your problem was caused by your “container_email” element being set to by the script to 140px.

Hopefully you can just change this in the editor (hard to debug without access!), but if not, the following CSS will fix it:

div#container_email {
width: 100% !Important
}

input#email {
width: 100% !Important
}

fieldset.step{
width: 100% !important
}

I also noticed the same thing happened to your checkbox, so this can be overridden as follows:

input[name="privacy_consent"] {
width: 20px !Important;
}

Here’s what I ended up with -

All the best,

Thank you very much Harvey! It works and looks exactly how I wanted. 😉

Any updates on this?

s there by any chance a way to automatically jump to next question without clicking “next” button on drop-down selections?

Hi,

Can any one give .unbounce page where this script is implemented?

Can you share .unbounce page of this to download? It will be great for this community and help us all.

Hi @adimpression,

Would you be able to share your resolution with the script not syncing with the form. I’m having the same issue and am not able to resolve it.

Thanks!

@Caroline!

Hi, would you know why I get the fields side by side instead of underneath each other? I’ve tried various things.

screenshot_4519|636x354

Thanks

Does anyone have a video of this process? I followed the instructions but can’t get it to work.

Hi there,

Progress bar does not appear at all, is this a common issue?

Thanks!

Badge

Does anyone know why the button is messed up when the forms fields are next to each other

See example here: http://unbouncepages.com/multi-step-help1234e/

The button always reverts to to the same spot and I can’t customise it

  1. Can someone please help me move my button to below the options?

  2. I can’t get the progress bar to work 😦

Page: https://www.trinitynetwork.co.nz/free-appraisal/

Badge +1

Unfortunately I can’t make it work.
Unbounce, it’s 2022 and we are still waiting for a solution...

This is great but why hasn’t unbounce added a native multistep form instead of relying on the community or work arounds? Clearly there is demand. 

Reply