Turn any webform into a powerful wizard with jQuery (FormToWizard plugin)

This detailed tutorial will show you how to turn long webform into a wizard with “steps left” information. A plugin is also available for download.

Download plugin with example  View demo

What is our task?

If you would, for whatever reason, have a large webform all fields shoud be semantically divided into fieldsets. Each fieldset would clearly describe each group of fields. Although many examples on the web today look different, this is how it should be.

 

So, we can say that each group of fields represent a sub task of a larger task – filling the entire web form. Thus, each sub task can become a step with a description, input fields and navigation that is common for wizard forms – back and next.The entire process can be done in several simple steps.

1. Create “steps”

The code should look like the example below.

<form id="SignupForm" action="">
    <fieldset>
        <-- input fields -->
    </fieldset>
    <fieldset>
        <-- input fields -->
    </fieldset>
    <fieldset>
        <-- input fields -->
    </fieldset>
</form> 

Let’s explain the following code. In order to determine how much steps there will be, we need to select all fieldsets and get the size of this wrapped set. Next, we iterate through this wrapped set (that returned all fieldsets), wrap each fieldset into a div and append a paragraph that will hold “back” and “next” buttons.

Now comes the funny part. If this is a first fieldset in wrapped set, we’ll create “next” button only and make this step visible. If it is the last fieldset in wrapped set, we’ll create only “back” button. In all other cases we’ll create both buttons. Methods for creating buttons will be explained later in this tutorial.

var steps = $("#SignupForm fieldset");
var count = steps.size();
steps.each(function(i) {     $(this).wrap("<div id='step" + i + "'></div>");     $(this).append("<p id='step" + i + "commands'></p>");
    if (i == 0) {         createNextButton(i);        // to do         selectStep(i);                  // to do     }     else if (i == count - 1) {         $("#step" + i).hide();         createPrevButton(i);       // to do     }     else {         $("#step" + i).hide();         createPrevButton(i);       // to do         createNextButton(i);       // to do } }

Now let’s explain how to create buttons and how users will actually move through the wizard.

2. Create next and back buttons and add interatcion

Creating the buttons isn’t that hard. Each button will have a unique name (e.g. step1next, or step3prev) and will be appended to their panels created in previous step. In order to add some interaction, and that is to enable moving between steps, we need to bind click event to each button. This is how they will work:

  • When user presses back button it will hide the current step, show the previous one and call selectStep() method which will mark it as current.
  • When user presses next button it will hide the current step, show the next one and call selectStep() method which will mark it as current.
function createPrevButton(i) {
    var stepName = "step" + i;
    $("#" + stepName + "commands").append("<a href='#' id='" + stepName + "Prev' class='prev'>< Back</a>");
    $("#" + stepName + "Prev").bind("click", function(e) {         $("#" + stepName).hide();         $("#step" + (i - 1)).show();         selectStep(i - 1);     }); }
function createNextButton(i) {     var stepName = "step" + i;     $("#" + stepName + "commands").append("<a href='#' id='" + stepName + "Next' class='next'>Next ></a>");     $("#" + stepName + "Next").bind("click", function(e) {         $("#" + stepName).hide();         $("#step" + (i + 1)).show();         selectStep(i + 1);     }); }

Function selectStep() that I mentioned before removes CSS class “current” from all steps and assign it only to the currently selected.

function selectStep(i) {
    $("#steps li").removeClass("current");
    $("#stepDesc" + i).addClass("current");
}

At this moment wizard is functional. But that’s not all. Let’s apply Steps left UI design pattern here.

3. Create “steps left” information

This is easier than it might look like at the first sight. At the very beginning of our code we have to add unordered list that will be a container for steps left information. In addition to this we will hide signup button. We want it to be visible only in the last step.

var steps = $("#SignupForm fieldset");
var count = steps.size();
           
$("#SaveAccount").hide();
$("#SignupForm").before("<ul id='steps'></ul>");

We also need to extend each() function and add information about steps for each fieldset in wrapped set. Each step will have it’s natural number, starting with 1. Below the step number we’ll add a description that is extracted from <legend> element.

steps.each(function(i) {
    var name = $(this).find("legend").html();
    $("#steps").append("<li id='stepDesc" + i + "'>Step " + (i + 1) + "<span>" + name + "</span></li>");
    ...
});

Let’s do just one more thing. Since submit button should be visible only in the last step, we’ll hide it every time user presses next. Only if user comes to the last step, it should be visible.

$("#" + stepName + "Prev").bind("click", function(e) {
    $("#SaveAccount").hide();
});
$("#" + stepName + "Next").bind("click", function(e) {
    if (i + 2 == count)
        $("#SaveAccount").show();
});

If you want to see the full source code, download it or check out the demo.

Plugin for easier use

It would be a pity not to create a plugin that will enable all of this in just one line of code. I called it FormToWizard. I guess it’s clear what it does :) In order to apply the plugin you will have to add a reference to script file and apply it to y <form> element.

<script type="text/javascript" src="formToWizard.js"></script>
$("#SignupForm").formToWizard();

If you want to hide a submit button (or placeholder for multiple buttons) you can add a parameter sumbitButton with the name of element you wish to be hidden.

$("#SignupForm").formToWizard({ submitButton: 'SaveAccount' }) 

Lightweight and Cross Browser compatible

This plugin has only 2,3KB and with compression it can be even smaller. It is compatible with all major browsers: FireFox, Google Chrome, Safari, Opera, Internet Explorer 8, 7 and 6. The latter is collateral, I was surprised it actually works there :)

If you, however, find any bug or have some suggestion on how to improve this or extend it, please share!

This work is published under Creative Commons Attribution 3.0 Unported License.