[How To] Add A Multi-Step Form 2.0


Userlevel 7
  • Former Unbouncer
  • 126 replies

When you’re building your landing pages in Unbounce, you want the conversion process to be as simple as possible. Nothing too distracting, and you certainly don’t want to scare your audience away with long, time-consuming forms.

We’ve built an easy solution for you because, hey, we’re marketers too! :unbounce:

Introducing Multi-Step Forms! 📈 🎉

No more scary, conversion killing forms!
Follow the steps below to implement this handy script into your landing page and try it for yourself! And, as always, remember to A/B test, and keep us posted on your results!

You can see this in action (built in Unbounce) here:


How to Install in Unbounce

Click Here for Instructions

🚨
This is not an official Unbounce feature. This functionality is based entirely on third party code, and has only been tested in limited applications. Since this isn’t a supported Unbounce feature, our support team will be unable to assist if things go awry. So if you are not comfortable with HTML, Javascript and CSS, please consider consulting an experienced developer.


Step 1.

Create your form in Unbounce.

Step 2.

Create a new button element for your ‘Next’ button and one for your ‘Previous’ button. Keep in mind when positioning these buttons (and your form submission button) that only one field will be shown at a time.

Step 3.

Copy this script and paste it into the Javascripts section of your page with placement ‘Before Body End Tag’:

<script type="text/javascript" src="https://rawgit.com/kimmobrunfeldt/progressbar.js/1.0.0/dist/progressbar.js"></script>

<script>
  (function() {
    // Update the following IDs with your own button IDs
    var backButton = document.getElementById('lp-pom-button-14');
    var nextButton = document.getElementById('lp-pom-button-13');
    var showProgressBar = false;

    var submitButton = document.querySelector('.lp-pom-form .lp-pom-button');
    var formContainer = document.querySelector('.lp-element .lp-pom-form');
    var currentField = 0;
    var allFields = document.getElementsByClassName('lp-pom-form-field');
    var errorSpan = document.createElement('span');

    for (i = 0; i < allFields.length; i++) {
      allFields[i].classList.add('hide');
      allFields[i].style.top = '0px';
    }

    backButton.classList.add('hide');
    submitButton.classList.add('hide');

    allFields[0].classList.remove('hide');

    if (allFields[0].querySelector('input')) {
      allFields[0].querySelector('input').focus();
    }

    errorSpan.classList.add('hide');
    errorSpan.style.color = 'red';
    errorSpan.style.position = 'absolute';
    var labelHeight;
    if (allFields[0].querySelector('label')) {
      labelHeight = allFields[0].querySelector('label').clientHeight;
    } else {
      labelHeight = 25;
    }
    errorSpan.style.top = '-' + labelHeight + 'px';
    formContainer.appendChild(errorSpan);

    if (showProgressBar) {
      var progressContainer = document.createElement('div');
      progressContainer.id = 'container';
      formContainer.appendChild(progressContainer);

      var bar = new ProgressBar.Line(container, {
        strokeWidth: 4,
        easing: 'easeInOut',
        duration: 1400,
        color: '#FFEA82',
        trailColor: '#eee',
        trailWidth: 1,
        svgStyle: { width: '100%', height: '100%' },
        from: { color: '#FFEA82' },
        to: { color: '#74D16A' },
        text: {
          style: {
            // Text color.
            // Default: same as stroke color (options.color)
            color: '#fff',
            position: 'absolute',
            right: '0',
            top: '30px',
            padding: 0,
            margin: 0,
            transform: null,
          },
          autoStyleContainer: false,
        },
        step: function(state, bar) {
          bar.setText(currentField + 1 + ' of ' + allFields.length);
          bar.path.setAttribute('stroke', state.color);
        },
      });
    }

    function nextEvent() {
      allFields[currentField].classList.add('hide');

      currentField += 1;
      allFields[currentField].classList.remove('hide');
      if (allFields[currentField].querySelector('input')) {
        allFields[currentField].querySelector('input').focus();
      }

      if (currentField > 0) {
        backButton.classList.remove('hide');
      }

      if (currentField === allFields.length - 1) {
        submitButton.classList.remove('hide');
        nextButton.classList.add('hide');
      }

      updateProgress();
    }

    function backEvent() {
      allFields[currentField].classList.add('hide');
      submitButton.classList.add('hide');

      currentField -= 1;
      allFields[currentField].classList.remove('hide');
      if (allFields[currentField].querySelector('input')) {
        allFields[currentField].querySelector('input').focus();
      }
      if (currentField === 0) {
        backButton.classList.add('hide');
        nextButton.classList.remove('hide');
      }
      if (currentField <= allFields.length - 1) {
        nextButton.classList.remove('hide');
      }

      updateProgress();
    }

    function currentFieldInvalid() {
      var invalidInput = allFields[currentField].querySelector(':invalid');

      if (invalidInput) {
        errorSpan.textContent = invalidInput.validationMessage;
      }

      return Boolean(invalidInput);
    }

    function updateProgress() {
      if (showProgressBar) {
        var barSize = (currentField + 1) / allFields.length;
        bar.animate(barSize); // Number from 0.0 to 1.0
      }
    }

    updateProgress();

    nextButton.addEventListener('click', function(e) {
      if (currentFieldInvalid()) {
        if (allFields[currentField].querySelector('input')) {
          allFields[currentField].querySelector('input').classList.add('hasError');
        } else {
          allFields[currentField].children[1].classList.add('hasError');
        }

        errorSpan.classList.remove('hide');
        e.preventDefault();
      } else {
        if (allFields[currentField].querySelector('input')) {
          allFields[currentField].querySelector('input').classList.remove('hasError');
        } else {
          allFields[currentField].children[1].classList.remove('hasError');
        }

        errorSpan.classList.add('hide');
        nextEvent();
      }
    });

    backButton.addEventListener('click', backEvent);

    submitButton.addEventListener('click', function(e) {
      if (currentFieldInvalid()) {
        if (allFields[currentField].querySelector('input')) {
          allFields[currentField].querySelector('input').classList.add('hasError');
        } else {
          allFields[currentField].children[1].classList.add('hasError');
        }

        errorSpan.classList.remove('hide');
        e.preventDefault();
      } else {
        if (allFields[currentField].querySelector('input')) {
          allFields[currentField].querySelector('input').classList.remove('hasError');
        } else {
          allFields[currentField].children[1].classList.remove('hasError');
        }

        errorSpan.classList.add('hide');
      }
    });

    document.body.addEventListener('keydown', function(e) {
      var keyCode = e.keyCode || e.which;

      // Enter key
      if (keyCode === 13 && currentField < allFields.length - 1) {
        if (currentFieldInvalid()) {
          if (allFields[currentField].querySelector('input')) {
            allFields[currentField].querySelector('input').classList.add('hasError');
          } else {
            allFields[currentField].children[1].classList.add('hasError');
          }

          errorSpan.classList.remove('hide');
          e.preventDefault();
        } else {
          if (allFields[currentField].querySelector('input')) {
            allFields[currentField].querySelector('input').classList.remove('hasError');
          } else {
            allFields[currentField].children[1].classList.remove('hasError');
          }

          errorSpan.classList.add('hide');
          e.preventDefault();
          nextEvent();
        }
      } else if (keyCode === 13 && currentField === allFields.length - 1) {
        if (currentFieldInvalid()) {
          if (allFields[currentField].querySelector('input')) {
            allFields[currentField].querySelector('input').classList.add('hasError');
          } else {
            allFields[currentField].children[1].classList.add('hasError');
          }

          errorSpan.classList.remove('hide');
          e.preventDefault();
        } else {
          if (allFields[currentField].querySelector('input')) {
            allFields[currentField].querySelector('input').classList.remove('hasError');
          } else {
            allFields[currentField].children[1].classList.remove('hasError');
          }

          errorSpan.classList.add('hide');
        }
      }

      if (keyCode === 37) {
        // Left key
        if (currentField > 0) {
          backEvent();
        }
      } else if (keyCode === 39) {
        // Right key
        if (currentField < allFields.length - 1) {
          if (currentFieldInvalid()) {
            if (allFields[currentField].querySelector('input')) {
              allFields[currentField].querySelector('input').classList.add('hasError');
            } else {
              allFields[currentField].children[1].classList.add('hasError');
            }

            errorSpan.classList.remove('hide');
            e.preventDefault();
          } else {
            if (allFields[currentField].querySelector('input')) {
              allFields[currentField].querySelector('input').classList.remove('hasError');
            } else {
              allFields[currentField].children[1].classList.remove('hasError');
            }

            errorSpan.classList.add('hide');
            nextEvent();
          }
        }
      }
    });
  })();

  /**
   * Do not remove this section; it allows our team to troubleshoot and track feature adoption.
   * TS:0002-03-062
   */
</script>

Step 4.

Update the script with the ID of your ‘Previous’ and ‘Next’ button elements. Tip: Make sure you exclude the ‘#’ in the ID.

Step 5.

Copy this script and paste it into the Stylesheets section of your page:

<style>
  #container {
    margin-top: -45px;
    width: 100%;
    height: 8px;
    position: relative;
  }
  .lp-form-errors {
    display: none !important;
  }
  .hasError {
    border: 1px solid tomato !important;
    box-shadow: 0px 0px 5px 1px tomato !important;
  }
  .hide {
    display: none !important;
  }
  .lp-pom-form-field,
  .lp-pom-button {
    -webkit-animation: KEYFRAME-NAME 2s;
    -moz-animation: KEYFRAME-NAME 2s;
    -o-animation: KEYFRAME-NAME 2s;
    animation: KEYFRAME-NAME 2s;
  }

  @-webkit-keyframes KEYFRAME-NAME {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }
  @-moz-keyframes KEYFRAME-NAME {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }
  @-o-keyframes KEYFRAME-NAME {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }
  @keyframes KEYFRAME-NAME {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }
</style>

You’re done!

Now sit back and let the conversions roll in… :gif_master:


Can’t see the instructions? Log in or Join the Community to get access immediately. 🚀


Want to take your Unbounce landing pages + Convertables™ to the next level?
:spinbounce: Check out the Ultimate List of Unbounce Tips, Scripts & Hacks


224 replies

Nevermind, it works. I was putting it after body tag. It should be included inside the body tag.

Any way to make it so that sometimes it shows a cluster of fields?

For example you have a survey and then at the end you want to pop out the email, name, phone # fields all at once.

Thanks for the form and script. I am having problem with the drop-down menu. the form works up to the drop-down and then it won’t go any further. please advise

thank you

Userlevel 7

@TheRawr, no solution for that at the moment but will update this post if that changes!

Userlevel 7

Hey @Samir, it looks like there was a small bug caused by the inline form validation. I’ve updated the script (found here: https://gist.github.com/noahub/b8c6d63abb50048d42ee721c900450df). Could you give it a try and let me know if your issue is resolved?

Brand new to unbounce (not a tech specialist) and wish some clarity around form design. I wish to do a two part form from the landing page. Step 1 would standard information gathering (multiple fields) then once they click on 'next ’ (input data collected at this point) a new form would appear with some options (multiple fields) from which they can choose. Can this be done OR is as I think I have read one form only per landing page? Thanks

Hi all,

I’m trying to achieve this effect, but the actual form isn’t showing?

http://promotions.futurefit.co.uk/bl4nk-p4g3330/

The previous, next and form submission buttons are showing but the actual field isn’t.

Any ideas?

Many thanks,

Jack

Userlevel 7

Hey Jack, it looks like you may simply need to remove the ‘#’ from the IDs in the back and next ‘getElementById’ methods (lines 3+4 of the js).

Hey guys!

We have seen first hand that multi-step forms are a powerful tactic to increasing conversion rates, especially if you can get the user to invest themselves in the first couple of fields (often asking the user for the less commitment based fields first).

With that in mind, is there anyway to display more than 1 field at a time? As it stands right now I can’t see this feature working for much of our clients as one of the primary reasons for using a multi-step field is to break down the form into manageable chunks. For instance, If we had 9 fields to capture from the user that would require them to click the next button 9 times.

I’m excited to see how this feature develops!

Hi Noah,
Thanks so much for fixing the bug, the drop down menu is now working as
well. If we get the progress bar and possibility of showing more than one field
at the time, that would be great!

Badge +1

Hey @Noah!

Having some trouble with the next button function.

It’s visible but it doesn’t display the next field or the ‘back’ button.

Userlevel 7

Hey @Alan_C, feel free to direct message me with a link to your page and I can try to identify what’s going on here!

@Noah have you considered creating a seperate script for inline error messages as the default error messages styling offered by unbounce is pretty old school by now?

Userlevel 7

@nik_adiko good idea! I’ll let you know if I come up with something 🙂

@Noah wonderful code, it is a beaut and filling a huge gap Unbounce has.

But sadly I had to remove it from my landing pages with more than 3 field forms. I realized I’m missing a good portion of the abandoned data. I’ll implement back on if I manage to find a practical way to access this data.

Userlevel 7

Hey @nik_adiko good news, a new post is up for inline error messages: [How to] Add Inline Form Error Messages. Take a look and let me know what you think!

Will this work on a convertables? I added it to the exit overlay but the script doesn’t seem to be working. http://lowercholesterolnaturally.futureceuticalsdirect.com/remove-more-cholesterol-sse/

Userlevel 7

@jsuppes I haven’t seen any issues so far. It looks you may just need to change the placement of your script to ‘Before Body End Tag’

Thanks Noah, that did the trick!

@Noah Noah! Just got this script implemented on a page and it’s working wonderfully, great code.

I have a quick question, though. Is the information submitted step by step as well or only carried through after the form has been submitted?

For example, if they fill out their Email and Name, then back out at the phone number phase, does the email and name carry through so that they can still be contacted, or is no information whatsoever passed until the submit button? If it doesn’t do this naturally, is there an extra snip of code that would? If I am misunderstanding something here, please feel free to enlighten!

Badge

@aclayton did you ever figure this out? I read through this thread and don’t think I saw a response. @Noah any help on this? An alternative to a progress bar is maybe to change the button for each step so that we can customize the copy on it? Just a thought for a workaround if progress bar isn’t possible…

Hello, is there anyway to record what people have started filling in, even if they dropped before the end of form ?

Userlevel 7
Badge +3

Hi @Etienne,

There is no way for you to access the data from an unfinished form.

Best,
Hristian

hello. Trying to implement this -> can’t get past the first ‘next’ button.

http://www.solidfire.business/microsoft365-form-2/

Any help greatly appreciated 🙂

Userlevel 7

it looks like the script didn’t play nicely with hidden form labels 😐 The latest version here should fix this: https://gist.github.com/noahub/b8c6d63abb50048d42ee721c900450df

Reply