How to make amazing multi-step forms for Mailchimp (for free without plugins)

Have you ever wanted to be able to break a large newsletter sign-up form up into smaller steps? I know I have!

It can seem very daunting for a user to be met by something like this when they want to sign up:

Illustration of a large MailChimp form with many fields

There are just too many fields. You run the risk of losing the potential lead completely if you present a form like that. But what if you really want to capture all that information? What if you need that information from your leads. Is there a way to make it easier for them?

ABSOLUTELY.

You can break the form down into smaller steps. That way the user will not be overwhelmed. This also means that you will get more sign-ups on large forms. A user that has started filling out a form is more likely to finish it, even though they have to go through several steps.

But how do you do it?

Introducing free multi-step forms for Mailchimp

I am going to use MailChimp as an example in this article. This is because it’s free to start and a lot of people use it. Rest assured that all of the tricks in this article can be used on other platforms that allow inline forms, like ActiveCampaign for instance.

This is a tutorial on how to get a completely free multi-step form for newsletter sign-ups on your website, without using plugins. This is my way of doing it, so there might be other ways. I think my way works just fine.

Now, since this is free, you need to do some coding. But fret not! We will make it easy and break it down into simple steps. Trust me when I say that doing this yourself is much easier and cheaper than paying for a subscription you don’t need and trying to integrate that tool through Zapier to get it to work.

The best thing is that this will work on any CMS that allows you to insert code. I am going to use WordPress for my example. All the code including an example is available at the end of this article.

I strongly suggest that you follow along though. You will learn something useful and you will understand what is going on with the code.

I am going to assume that you know the basics of WordPress, like how to access your functions.php file and that you are using a child theme or custom-built theme that will not be overwritten because of updates.

What you need to get started:

  • An account with your favorite ESP. I’ll use MailChimp.
  • A text editor. I’ll use Notepad++.
  • Access to your server. I’ll use FTP-access with FileZilla.
  • Some patience and an open mind.

Creating your multi-step form

The first thing you want to do is make a form with all the fields you need to be able to capture the information you want. How to do this can be found on the website of the tool you are using. I will not go into that here.

Just be sure to think ahead a bit. How many steps do you want, and what fields to you want to group together? Make sure to fill the form with fields in the right order. I’ll use the form at the start of this article for this example.

We are going to make this into a multi-step form by adding what is called “fieldsets” around the fields we want to group together. We are also going to add our own “Next”-button that handles the logic of navigating the form.

We will validate the user input at each stage of the form and display our own error message or visual cue if the step lacks info. This way we can ensure that all fields are filled in before the last step where the user can submit the form.

Creating the fields for the form

Start by going into MailChimp and choose “Embedded forms”. Now you should see some code you can copy. This is your form. Create a new HTML-file in your text editor and paste the code there. We are going to do some tweaks.

You can choose to keep or remove the styles at the start. I’ll just remove them for simplicity. This tutorial will be focused on the logic of the form, but I will also go over some styling at the end.

Try to locate the sections of the code that reads something like this:

<div class="mc-field-group">
	<label for="mce-FNAME">First Name </label>
	<input type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>Code language: JavaScript (javascript)

These code blocks are your fields. The only thing you need to do next is to wrap them with fieldset tags. So the code above would look like this:

<fieldset>
<div class="mc-field-group">
	<label for="mce-FNAME">First Name </label>
	<input type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>
</fieldset>Code language: HTML, XML (xml)

Each fieldset-block is a step in your multi-step form. So you should group your blocks in the way that you want them to show up in the form. This is my example for the whole form:

<fieldset>
<div class="mc-field-group">
	<label for="mce-EMAIL">Email Address  <span class="asterisk">*</span>
</label>
	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
</fieldset>
<fieldset>
<div class="mc-field-group">
	<label for="mce-FNAME">First Name </label>
	<input type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>
</fieldset>
<fieldset>
<div class="mc-field-group">
	<label for="mce-LNAME">Last Name </label>
	<input type="text" value="" name="LNAME" class="" id="mce-LNAME">
</div>
<div class="mc-field-group size1of2">
	<label for="mce-MMERGE4">Phone Number </label>
	<input type="text" name="MMERGE4" class="" value="" id="mce-MMERGE4">
</div>
</fieldset>
<fieldset>
<div class="mc-field-group input-group">
    <strong>Are you interested in honey? </strong>
    <ul><li><input type="radio" value="Yes" name="WELCOME1" id="mce-WELCOME1-0"><label for="mce-WELCOME1-0">Yes</label></li>
<li><input type="radio" value="No" name="WELCOME1" id="mce-WELCOME1-1"><label for="mce-WELCOME1-1">No</label></li>
</ul>
</div>
</fieldset>
<fieldset>
<div class="mc-field-group input-group">
    <strong>Choose your poison </strong>
    <ul><li><input type="checkbox" value="1" name="group[3427][1]" id="mce-group[3427]-3427-0"><label for="mce-group[3427]-3427-0">Milk</label></li>
<li><input type="checkbox" value="2" name="group[3427][2]" id="mce-group[3427]-3427-1"><label for="mce-group[3427]-3427-1">Papercut</label></li>
<li><input type="checkbox" value="4" name="group[3427][4]" id="mce-group[3427]-3427-2"><label for="mce-group[3427]-3427-2">Five liters of wood</label></li>
<li><input type="checkbox" value="8" name="group[3427][8]" id="mce-group[3427]-3427-3"><label for="mce-group[3427]-3427-3">Penguins</label></li>
<li><input type="checkbox" value="32" name="group[3427][32]" id="mce-group[3427]-3427-4"><label for="mce-group[3427]-3427-4">Sofa</label></li>
</ul>
</div>
</fieldset>Code language: HTML, XML (xml)

Since we want to be able to target individual fieldsets to either show or hide them, we need to add an ID to each one. I will name the ID’s from “step_1” to “step_5” to cover them all.

In addition to this, we want all of our fieldsets to start hidden, except the first. To do this, you also add the class “hidden” to all the fieldsets except the first:

<fieldset id="step_1">
<div class="mc-field-group">
	<label for="mce-EMAIL">Email Address  <span class="asterisk">*</span>
</label>
	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
</fieldset>
<fieldset id="step_2" class="hidden">
<div class="mc-field-group">
	<label for="mce-FNAME">First Name </label>
	<input type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>
</fieldset>Code language: HTML, XML (xml)

At the very top of the code, you should find the style section that I mentioned earlier. If you removed it, you can just add your own back in. We need to hide the hidden fields. It should look like this:

<style type="text/css">
    .hidden {
        display: none;
    }
</style>Code language: HTML, XML (xml)

Great! Now we want to add our own button. We want it to have an ID we can use, and to be of the type “button” so that a click will not try to submit the form. Insert this code below the last fieldset:

<button id="next-button" type="button">Next</button>Code language: HTML, XML (xml)

Finally, put the MailChimp submit button after the next button and give it the hidden class. Remove what you don’t need (like headings, labels, ul/li tags, and text). You can also add some placeholders. The whole code now looks like this:

<!-- Begin Mailchimp Signup Form -->
<style type="text/css">
    .hidden {
        display: none;
    }
</style>
<div id="mc_embed_signup">
<form action="[HIDDEN FOR PRIVACY]" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
    <div id="mc_embed_signup_scroll">
<fieldset id="step_1">
<div class="mc-field-group">
	<input placeholder = "Your email" type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
</fieldset>
<fieldset id="step_2" class="hidden">
<div class="mc-field-group">
	<input placeholder = "Your first name" type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>
</fieldset>
<fieldset id="step_3" class="hidden">
<div class="mc-field-group">
	<input placeholder = "Your last name" type="text" value="" name="LNAME" class="" id="mce-LNAME">
</div>
<div class="mc-field-group size1of2">
	<input placeholder = "Your number" type="text" name="MMERGE4" class="" value="" id="mce-MMERGE4">
</div>
</fieldset>
<fieldset id="step_4" class="hidden">
<div class="mc-field-group input-group">
<strong>Are you interested in honey?</strong>
<label for="mce-WELCOME1-0"><input type="radio" value="Yes" name="WELCOME1" id="mce-WELCOME1-0">Yes</label>
<label for="mce-WELCOME1-1"><input type="radio" value="No" name="WELCOME1" id="mce-WELCOME1-1">No</label>
</div>
</fieldset>
<fieldset id="step_5" class="hidden">
<div class="mc-field-group input-group">
    <strong>Choose your poison</strong>
<label for="mce-group[3427]-3427-0"><input type="checkbox" value="1" name="group[3427][1]" id="mce-group[3427]-3427-0">Milk</label>
<label for="mce-group[3427]-3427-1"><input type="checkbox" value="2" name="group[3427][2]" id="mce-group[3427]-3427-1">Papercut</label>
<label for="mce-group[3427]-3427-2"><input type="checkbox" value="4" name="group[3427][4]" id="mce-group[3427]-3427-2">Five liters of wood</label>
<label for="mce-group[3427]-3427-3"><input type="checkbox" value="8" name="group[3427][8]" id="mce-group[3427]-3427-3">Penguins</label>
<label for="mce-group[3427]-3427-4"><input type="checkbox" value="32" name="group[3427][32]" id="mce-group[3427]-3427-4">Sofa</label>
</div>
</fieldset>
<button id="next-button" type="button">Next</button>
<div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-example-embedded-subscribe" class="button hidden"></div>
	<div id="mce-responses" class="clear">
		<div class="response" id="mce-error-response" style="display:none"></div>
		<div class="response" id="mce-success-response" style="display:none"></div>
	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
    <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_7cf9a12dd3fac574d460609a4_afd4dec417" tabindex="-1" value=""></div>
    
    </div>
</form>
</div>
<script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[2]='LNAME';ftypes[2]='text';fnames[4]='MMERGE4';ftypes[4]='phone';fnames[3]='WELCOME1';ftypes[3]='radio';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
<!--End mc_embed_signup-->Code language: HTML, XML (xml)

That’s it. We are now done with the form and need to do some logic. Create a new empty JavaScript-file (whatever.js). We are going to use jQuery to handle much of the logic. This is included in WordPress by default, but you might need to include it if you are using another CMS or building your own website.

Just add this code to your header if you need to include jQuery:

<script
  src="https://code.jquery.com/jquery-3.4.1.min.js"
  integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
  crossorigin="anonymous"></script>Code language: HTML, XML (xml)

Handling the logic for the multi-step MailChimp-form

I’m going to assume that WordPress is used. We need to wrap all our code in a specific function that allows us to use jQuery “normally”. We also want the browser to be done loading the page before executing our code. Both of these things are solved by starting your empty JavaScript-file with this function:

jQuery(document).ready(function( $ ) {

	//Your code here

});Code language: JavaScript (javascript)

The first thing we want is a function that can handle hiding all fieldsets in the form. Let’s just call it “hideAll”. It’s really simple:

jQuery(document).ready(function( $ ) {

	function hideAll() {
	    $('fieldset').addClass('hidden');
    }

});Code language: JavaScript (javascript)

We use jQuery ($) to find all fieldsets, and we add the class “hidden” to all of them. This will hide our fields. Since this is a function it will not run when the page has finished loading. We can control where we want it to run by calling the function.

The next thing we are going to create is a function that can handle showing the correct fields. To do this we need to hide all the fieldsets before removing the “hidden”-class from the fieldset we want to show:

function setStep(nextStepID) {
	hideAll();
	$('fieldset#' + nextStepID).removeClass('hidden');
}Code language: JavaScript (javascript)

We are going to fetch the ID of the next step in another function. What we are essentially doing here is as simple as calling the “hideAll”-function to hide all of the steps, and then removing the “hidden”-class for the next step.

The only thing that is left to get this up and running is basically telling the browser to do this logic when clicking our “Next”-button. We will add yet another function to our JavaScript-file:

$( "#next-button" ).click(function() {
    
});Code language: JavaScript (javascript)

This function runs when we click an element with the ID “next-button”. This is the exact ID of the button we made earlier. What is the first thing we want to happen? Well, we certainly need to know what step we are at currently:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
});Code language: JavaScript (javascript)

This code defines a variable named “currentStep” and fills it with the ID of any fieldset that is not hidden. Since we only show one fieldset at a time, we get the ID of the current step. We can use this ID to find the next step:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
    var nextStep = $('#' + currentStep).next("fieldset").attr('id');
});Code language: JavaScript (javascript)

The variable called “nextStep” gets filled with the ID of the fieldset that comes after the current one in the code. It can seem complicated, but it is really not. If you just read the code left to right, we are basically telling the computer to find the current step, check for the next fieldset and find the ID of that fieldset.

We now have the ID of the next step. We can use that info to navigate the form. Remember the “setStep” function that we made earlier? We can pass the next step ID to that function like this:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
    var nextStep = $('#' + currentStep).next("fieldset").attr('id');
    
    setStep(nextStep);
    
});Code language: JavaScript (javascript)

This is basically all you need to show the next step when clicking the button. This is a great start, but we are not done yet. We need to hide the button when we get to the end of the form. Otherwise, we will end up with two buttons. One next button and one submit button. We only need the latter.

We will use a switch statement to check what step we are currently on to hide the button at the right time. This switch statement will also be used for error handling later.

Now, we want to hide the next button after clicking it at the penultimate step. We also want to show the submit button:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
    var nextStep = $('#' + currentStep).next("fieldset").attr('id');
    
    setStep(nextStep);
    
    switch (currentStep) {
		
		case "step_4":
			$('#next-button').addClass('hidden');
			$('input[type=submit]').removeClass('hidden');
		break;
		
	}
    
});Code language: JavaScript (javascript)

My form has five fieldsets. We want to hide the button after clicking it at the fourth step. The code above checks what step we are on using the “currentStep” variable.

In the case that we are at step number four, the button will be hidden by adding the class “hidden” to it. It will also show the submit button by removing the “hidden”-class.

We are now done with the basic steps of creating a multi-step form. This might be enough for your specific case. I still think you should read on. We are now going into something that is really powerful.

Adding validation and error handling to the form

Let’s be honest for a second. What we are basically doing is changing and building upon the code that MailChimp has provided. We are therefore going outside of some limits set by them to ensure proper submission of forms.

If you were to use your form as it is right now, it might work fine. But if you were to input an invalid email into the field in step number one, you run into trouble.

This is because the submit button is at the last step, and we have no way of getting back to the first step. So you basically end up with an error message and no way to return to fix the problem.

We could start coding a back button, but why bother? I think it is better to just check for valid input at each step before letting the user continue. We do that using the switch statement we made earlier. Since my email input box is at step number one, the code looks like this:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
    var nextStep = $('#' + currentStep).next("fieldset").attr('id');
    validation = true;
    
    setStep(nextStep);
    
    switch (currentStep) {
        
        case "step_1":
			$('fieldset#' + currentStep).find('input[type=email]').each(function(){
				
				var email = $(this).val();
				
				emailReg = /.{1,}@[^.]{1,}/;
				
				if(!emailReg.test(email) || email == '') {
					validation = false;
					$(this).addClass('error');
				}
			});
		break;
		
		case "step_4":
			$('#next-button').addClass('hidden');
			$('input[type=submit]').removeClass('hidden');
		break;
		
	}
    
});Code language: JavaScript (javascript)

You need to set the case to the step that has your email field. This code is basically checking for all input fields of type “email” and creating a variable containing the user input. Then we test this input based on a simple regular expression represented by the variable “emailReg”.

If this test fails or the field is empty, we set the variable “validation” to false and add the class “error” to the field. We can use this class later to display a visual cue to the user.

Please note that we set validation to true on line number 4. This way we always assume that everything is going well right up to the point where it isn’t.

If you test this you will spot a problem. The form continues to the next step even though the email doesn’t validate. We can fix this easily by moving the “setStep” function after the switch statement:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
    var nextStep = $('#' + currentStep).next("fieldset").attr('id');
    validation = true;
    
    switch (currentStep) {
        
        case "step_1":
			$('fieldset#' + currentStep).find('input[type=email]').each(function(){
				
				var email = $(this).val();
				
				emailReg = /.{1,}@[^.]{1,}/;
				
				if(!emailReg.test(email) || email == '') {
					validation = false;
					$(this).addClass('error');
				}
			});
		break;
		
		case "step_4":
			$('#next-button').addClass('hidden');
			$('input[type=submit]').removeClass('hidden');
		break;
		
	}
    
    setStep(nextStep);
});Code language: JavaScript (javascript)

Then we need to add a validation check to the “setStep”-function like this:

function setStep(nextStepID) {
	if (validation == true) {
		hideAll();
        $('fieldset input').removeClass('error');
		$('fieldset#' + nextStepID).removeClass('hidden');
	}
}Code language: JavaScript (javascript)

This code will check that everything is validated before continuing to the next step. It will also remove any error classes from the input fields for good measure. If the validation variable is set to false, nothing will happen in this function.

Lastly, we want to validate that no fields are empty, that all radio buttons are checked and that at least one checkbox is checked. We need to use the switch statement to do this. This is because we can’t validate fields that have not been shown to the user yet. The user would not be able to continue to the next step if we did that.

The easiest thing is to just map out all your steps like this:

$( "#next-button" ).click(function() {
    var currentStep = $("fieldset").not(".hidden").attr('id');
    var nextStep = $('#' + currentStep).next("fieldset").attr('id');
    validation = true;
    
    switch (currentStep) {
        
        case "step_1":
			$('fieldset#' + currentStep).find('input[type=email]').each(function(){
				
				var email = $(this).val();
				
				emailReg = /.{1,}@[^.]{1,}/;
				
				if(!emailReg.test(email) || email == '') {
					validation = false;
					$(this).addClass('error');
				}
			});
		break;
		
		case "step_2":
		    
		break;
		
		case "step_3":
		    
		break;
		
		case "step_4":
			$('#next-button').addClass('hidden');
			$('input[type=submit]').removeClass('hidden');
		break;
		
		case "step_5":
		    
		break;
		
	}
    
    setStep(nextStep);
    
});Code language: JavaScript (javascript)

Now analyze each step. Look at the code in your HTML-file and see what is contained within each step. You can see from my example that all my steps contain inputs. In your case, one of the steps could contain a select tag if you want a dropdown. You will need to change the code accordingly, but I am sure you can figure it out!

We will go through the code step by step. In my case, step 2 contains an input of type text. So the validation code would look like this:

case "step_2":

    $('fieldset#' + currentStep).find('input[type=text]').each(function(){
    	
    	if ($(this).val() !== '') {
    		$(this).removeClass('error');
    	} else {	
    		$(this).addClass('error');
    		validation = false;
    	}
    });

break;Code language: JavaScript (javascript)

If the user is at step 2, we check all the inputs of type text that is contained within the fieldset of that step. If the input field is not empty, we remove the error class. If it is empty, we add the error class and set validation to false.

By analyzing the HTML-code I can see that step 3 also contains input fields of type text. To avoid too much bloat in the code, I can just use this neat trick to run the code for both steps:

case "step_2":
case "step_3":

    $('fieldset#' + currentStep).find('input[type=text]').each(function(){
    	
    	if ($(this).val() !== '') {
    		$(this).removeClass('error');
    	} else {	
    		$(this).addClass('error');
    		validation = false;
    	}
    });

break;Code language: JavaScript (javascript)

Step 4 contains a radio button group. We want to check that one of the radio buttons is selected. Please note that we are using the input name and not type this time. This is because radio buttons that share the same name are grouped together. That makes us able to determine if one radio button inside a given group is checked:

case "step_4":
    
    if ($('fieldset#' + currentStep + ' input[name=WELCOME1]').is(":checked")) {
        $('.input-group').removeClass('error');
        $('#next-button').addClass('hidden');
    	$('input[type=submit]').removeClass('hidden');
	} else {
		$('.input-group').addClass("error");
		validation = false;
	}

break;Code language: JavaScript (javascript)

We also hide the next button and show the submit button after this step if everything validates.

Step 5 contains checkboxes. We want to see if at least one checkbox is checked. Now you might think we could just do this:

case "step_5":
    
    $('fieldset#' + currentStep).find('input[type=checkbox]').each(function(){
						
		if ($(this).is(":checked")) {
            $(this).removeClass('error');
		} else {
			$(this).addClass("error");
			validation = false;
		}
	});

break;Code language: JavaScript (javascript)

But we actually can’t. The code loops through all checkboxes and sets validation to false on every empty checkbox. The code would only work if the last checkbox is selected. We could solve this by just invoking the “setStep” function immediately after finding a checked checkbox:

case "step_5":
    
    $('fieldset#' + currentStep).find('input[type=checkbox]').each(function(){
						
		if ($(this).is(":checked")) {
            setStep(nextStep);
		} else {
			$(this).addClass("error");
		}
	});

break;Code language: JavaScript (javascript)

But there is a problem with doing that. We are at the last step. There is no next step. Another problem here is that the “error”-class is added to every checkbox. Let’s add it to the fieldset instead:

case "step_5":
    
    $('fieldset#' + currentStep).find('input[type=checkbox]').each(function(){
						
		if ($(this).is(":checked")) {
            setStep(nextStep);
		} else {
			$('fieldset#' + currentStep).addClass("error"); //Change this
		}
	});

break;Code language: JavaScript (javascript)

Since step 5 is the last step, the next button is hidden. This code fires when the next button is clicked, so we have no way to validate that one of our checkboxes are checked.

We could add a step 6 with the submit button alone, or we could just run this code on the submit button itself. I’ll choose the latter for this example. We need to make a new function and move all of the code from the case “step_5” into it.

Now remove all references to “setStep”. We don’t need those anymore because there is no next step. Also, note the code on line 5. This stops the form from submitting when clicking the submit button.

We want to control when to submit the form. We do this on line 12:

$( "input[type=submit]" ).click(function(e) {
    
  var currentStep = $("fieldset").not(".hidden").attr('id');
  
  e.preventDefault();
  
  $('fieldset#' + currentStep).find('input[type=checkbox]').each(function(){
						
		if ($(this).is(":checked")) {
		    $('fieldset#' + currentStep).removeClass("error"); //Add this
            $("#mc-embedded-subscribe-form").submit(); //Add this
            return false; //Stops looping through checkboxes
		} else {
			$('fieldset#' + currentStep).addClass("error");
		}
	});
	
});Code language: JavaScript (javascript)

That should be it. The form now works as expected and all fields are validated. Sadly, it looks pretty bleak. Let’s fix that!

Making your form pretty

We can style the form either by using our own stylesheet or by adding styles directly in the code above, just as we did with the “hidden”-class. For simplicity, the latter is what I’ll do in this example.

The first thing we need to do is to add the visual cue for failed validation:

<style type="text/css">

    .hidden {
        display: none;
    }
    
    .error {
        border: 2px solid red !important;
    }
    
</style>Code language: HTML, XML (xml)

I also want to style the input fields differently, fix the buttons, and remove the border around the fieldsets (including some other changes):

<style type="text/css">

    .hidden {
        display: none;
    }
    
    .error {
        border: 2px solid red !important;
    }
    
    fieldset {
        border: none;
    }
    
    input[type=text], input[type=email] {
        border: 1px solid #0769ad;
        border-radius: 5px;
    }
    
    input[type=radio], input[type=checkbox] {
        width: 20px;
        height: 20px;
    }
    
</style>Code language: HTML, XML (xml)

Including your multi-step form in WordPress

You now have two files. One is an HTML-file with the form. The other is the JavaScript-file that contains all the logic. You can include these files in any CMS or web project you might have. I have chosen to focus on WordPress in this guide.

To insert the form in WordPress you have to first include the JavaScript-file. Upload it to your server using your preferred method. Then open your functions.php and add the following code at the bottom (but before ?> if it exists):

wp_enqueue_script( 'script', get_stylesheet_directory_uri() . '/js/script.js', array ( 'jquery' ), 1.1, true);Code language: PHP (php)

This line of code assumes that the file is put in a folder called “js” inside your theme or child theme folder. It also assumes that the file is called script.js.

There are a lot of ways to include the HTML-code for the form. You can add it to your template files if you want. An approach that is easier and allows you to add it anywhere is creating a shortcode.

Keep your functions.php file open. Then upload your HTML-file to your theme or child theme folder. Change the extension from .html to .php and note the name of the file. Go back into your functions.php and add the following code at the bottom (again, before ?> if it exists):

function my_form_shortcode() {

   ob_start();

   get_template_part('form-file-name');

   return ob_get_clean();   

} 

add_shortcode( 'my_form_shortcode', 'my_form_shortcode' );Code language: JavaScript (javascript)

Change “form-file-name” to fit your file name. You can omit the file extension. Now you can insert your form anywhere you’d like by using this shortcode:

[my_form_shortcode]

Summary with complete code and example

If you have read the whole post, I applaud you. You hopefully have learned a lot. Let’s summarize our steps to get here:

  1. Create an embedded form in MailChimp
  2. Add fieldsets to define the steps of the form
  3. Hide all fieldsets except the first
  4. Add a custom next button
  5. Create a JavaScript-file to handle logic
  6. Style the form
  7. Enqueue the JavaScript-file in WordPress
  8. Create a shortcode for displaying the form

This is the complete code for the HTML-file (that you changed to PHP if you made a shortcode):

<!-- Begin Mailchimp Signup Form -->
<style type="text/css">
   .hidden {
        display: none;
    }
    
    .error {
        border: 2px solid red !important;
    }
    
    fieldset {
        border: none;
		margin: 0;
		padding: 0;
    }
    
    input[type=text], input[type=email] {
        border: 1px solid #0769ad;
        border-radius: 5px;
		margin: 10px 0;
		padding: 10px;
		width: 100%;
    }
    
    input[type=radio], input[type=checkbox] {
        width: 20px;
        height: 20px;
    }
	
	label {
		display: block;
	}
	
	.input-group {
		margin: 10px 0;
	}
	
	input[type=submit], button {
		border: 2px solid #0769ad;
		border-radius: 5px;
		background: #fff;
		cursor: pointer;
		padding: 10px;
	}
	
	input[type=submit]:hover, button:hover {
		background: #0769ad;
		color: #fff;
	}
</style>

<div id="mc_embed_signup">
<form action="[HIDDEN FOR PRIVACY]" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
    <div id="mc_embed_signup_scroll">
<fieldset id="step_1">
<div class="mc-field-group">
	<input placeholder = "Your email" type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
</fieldset>
<fieldset id="step_2" class="hidden">
<div class="mc-field-group">
	<input placeholder = "Your first name" type="text" value="" name="FNAME" class="" id="mce-FNAME">
</div>
</fieldset>
<fieldset id="step_3" class="hidden">
<div class="mc-field-group">
	<input placeholder = "Your last name" type="text" value="" name="LNAME" class="" id="mce-LNAME">
</div>
<div class="mc-field-group size1of2">
	<input placeholder = "Your number" type="text" name="MMERGE4" class="" value="" id="mce-MMERGE4">
</div>
</fieldset>
<fieldset id="step_4" class="hidden">
<div class="mc-field-group input-group">
<strong>Are you interested in honey?</strong>
<label for="mce-WELCOME1-0"><input type="radio" value="Yes" name="WELCOME1" id="mce-WELCOME1-0">Yes</label>
<label for="mce-WELCOME1-1"><input type="radio" value="No" name="WELCOME1" id="mce-WELCOME1-1">No</label>
</div>
</fieldset>
<fieldset id="step_5" class="hidden">
<div class="mc-field-group input-group">
    <strong>Choose your poison</strong>
<label for="mce-group[3427]-3427-0"><input type="checkbox" value="1" name="group[3427][1]" id="mce-group[3427]-3427-0">Milk</label>
<label for="mce-group[3427]-3427-1"><input type="checkbox" value="2" name="group[3427][2]" id="mce-group[3427]-3427-1">Papercut</label>
<label for="mce-group[3427]-3427-2"><input type="checkbox" value="4" name="group[3427][4]" id="mce-group[3427]-3427-2">Five liters of wood</label>
<label for="mce-group[3427]-3427-3"><input type="checkbox" value="8" name="group[3427][8]" id="mce-group[3427]-3427-3">Penguins</label>
<label for="mce-group[3427]-3427-4"><input type="checkbox" value="32" name="group[3427][32]" id="mce-group[3427]-3427-4">Sofa</label>
</div>
</fieldset>
<button id="next-button" type="button">Next</button>
<div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-example-embedded-subscribe" class="button hidden"></div>
	<div id="mce-responses" class="clear">
		<div class="response" id="mce-error-response" style="display:none"></div>
		<div class="response" id="mce-success-response" style="display:none"></div>
	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
    <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_7cf9a12dd3fac574d460609a4_afd4dec417" tabindex="-1" value=""></div>
    
    </div>
</form>
</div>
<script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='FNAME';ftypes[1]='text';fnames[2]='LNAME';ftypes[2]='text';fnames[4]='MMERGE4';ftypes[4]='phone';fnames[3]='WELCOME1';ftypes[3]='radio';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
<!--End mc_embed_signup-->Code language: HTML, XML (xml)

This is the complete code for the JavaScript-file that handles all the logic:

jQuery(document).ready(function( $ ) {
    
    /* Hide all fields */
    
	function hideAll() {
	    $('fieldset').addClass('hidden');
    }
    
   /* Handle hiding all fields and showing the next field */
    
    function setStep(nextStepID) {
    	if (validation == true) {
    		hideAll();
    		$('fieldset input').removeClass('error');
    		$('fieldset#' + nextStepID).removeClass('hidden');
    	}
    }
    
   /* Logic for the button including validation */
    
    $( "#next-button" ).click(function() {
        var currentStep = $("fieldset").not(".hidden").attr('id');
        var nextStep = $('#' + currentStep).next("fieldset").attr('id');
        validation = true;
        
        switch (currentStep) {
            
            case "step_1":
    			$('fieldset#' + currentStep).find('input[type=email]').each(function(){
    				
    				var email = $(this).val();
    				
    				emailReg = /.{1,}@[^.]{1,}/;
    				
    				if(!emailReg.test(email) || email == '') {
    					validation = false;
    					$(this).addClass('error');
    				}
    			});
    		break;
    		
            case "step_2":
            case "step_3":
            
                $('fieldset#' + currentStep).find('input[type=text]').each(function(){
                	
                	if ($(this).val() !== '') {
                		$(this).removeClass('error');
                	} else {	
                		$(this).addClass('error');
                		validation = false;
                	}
                });
            
            break;
    		
            case "step_4":
                
                if ($('fieldset#' + currentStep + ' input[name=WELCOME1]').is(":checked")) {
                    $('.input-group').removeClass('error');
                    $('#next-button').addClass('hidden');
                	$('input[type=submit]').removeClass('hidden');
            	} else {
            		$('.input-group').addClass("error");
            		validation = false;
            	}
            
            break;
        }
        
        setStep(nextStep);
    
    });
    
   /* Submit button logic handler */
    
    $( "input[type=submit]" ).click(function(e) {
		
	var currentStep = $("fieldset").not(".hidden").attr('id');
      
      /* Stop the submit action */
      
      e.preventDefault();
      
      /* Validate checkboxes */
      
      $('fieldset#' + currentStep).find('input[type=checkbox]').each(function(){
    						
    		if ($(this).is(":checked")) {
    		    /* Submit the form */
    		    $('fieldset#' + currentStep).removeClass("error");
                $("#mc-embedded-subscribe-form").submit();
                return false; /* Stops looping through checkboxes */
    		} else {
    			$('fieldset#' + currentStep).addClass("error");
    		}
    	});
    	
    });
    
});Code language: JavaScript (javascript)

The standard MailChimp success response will appear. With some grit and determination, you will be able to create your own. You could perhaps hide the whole form and show a message after a successful submission?

And finally, here is an example as promised (this is not active and will not submit anything):

You now have the power to make your own completely free multi-step forms for any email service provider and include them in any CMS or web project!

Get these knowledge bombs before they are released

Plus exclusive content only for newsletter family members! No spam or yucky sales tactics. The bombs only drop occasionally for a clutter-free inbox.