#1 Rated Digital Marketing Agency in Colorado. Trusted by Top Brands for Maximum Growth & Superior Results.

How to Create a Bootstrap 5.3 Multi-Step Form

bootstrap 5.3 multi-step form
Jump to Section
  1. Section 1: Set Up the Bootstrap Environment
  2. Section 2: Structuring the Form
  3. Section 3: Navigating Between Form Steps
  4. Section 4: Updating the Progress Bar
  5. Section 5: Adding Transitions Between Steps
  6. Section 6: Submitting the Form
  7. Section 7: Bonus Features
  8. Full Code – Copy & Paste

Introduction

Multi-step forms are an effective way to enhance user experience, especially when you have to collect a large amount of information. Instead of overwhelming users with long, complex forms, a multi-step form breaks the process into smaller, more manageable steps. This approach not only makes the form easier to fill out, but it also helps reduce form abandonment rates, especially on mobile devices.

In this tutorial, we’ll walk you through how to create a multi-step form with a dynamic progress bar using Bootstrap 5.3. By the end of this guide, you’ll have a fully functional, responsive form that visually tracks the user’s progress and validates each step before submission.

Benefits of Multi-Step Forms

  • Improved user experience: Breaking down forms makes them less intimidating and easier to complete.
  • Higher conversion rates: Multi-step forms have been shown to reduce form abandonment and increase user engagement.
  • Progress visibility: Users can see how far they’ve progressed and how many steps remain, providing motivation to complete the form.
  • Increased lead quality and reduced spam: By tracking conversions only at the final form submission step, you can fully ensure your conversions are higher quality leads and prevent unwanted spam from being counted as conversions. This ensures more accurate data in Google Ads when tracking conversions.
  • Remarketing opportunities: Multi-step forms allow you to track users who don’t complete the form, creating opportunities for targeted remarketing audiences to re-engage those users and guide them back to complete the form.

Let’s get started by setting up the environment and laying out the basic structure of the form.

Section 1: Setting Up the Bootstrap 5 Environment

Step 1: Install Bootstrap 5

Before we start building the multi-step form, we need to set up Bootstrap 5. You can use either a Content Delivery Network (CDN) to quickly include Bootstrap or install it locally if you’re working on a more extensive project.

Option 1: Using Bootstrap 5 via CDN

If you’re building a simple project or just experimenting with Bootstrap 5, using a CDN is the quickest and easiest method. Add the following <link> and <script> tags to your HTML file:

<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Multi-Step Form</title>

<!-- Bootstrap 5 CDN -->

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>

</head>
<body>

<!-- Your content here -->

</body>
</html>

Option 2: Installing Bootstrap 5 Locally

For larger projects, it’s better to install Bootstrap 5 locally using npm or simply downloading the source files. To install using npm, run:

npm install bootstrap@5

Then, import Bootstrap in your JavaScript file:

import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.bundle.min.js';

Once Bootstrap is included in your project, you can start using its components and utility classes to build the multi-step form.

Step 2: Create the Basic HTML Structure

Now that Bootstrap 5 is set up, we need to create the basic structure of our multi-step form. We’ll use Bootstrap’s grid system to make the form responsive across all device sizes. Additionally, we’ll include a form container to house our inputs and navigation buttons.

Here’s the basic layout of the form:

<body>
  <div class="container mt-5">
    <h2 class="text-center mb-4">Multi-Step Form Example</h2>
    <form id="multiStepForm">
      <!-- Step 1 -->
      <div class="form-step active">
        <div class="mb-3">
          <label for="firstName" class="form-label">First Name</label>
          <input type="text" class="form-control" id="firstName" required>
        </div>
        <div class="mb-3">
          <label for="lastName" class="form-label">Last Name</label>
          <input type="text" class="form-control" id="lastName" required>
        </div>
        <button type="button" class="btn btn-primary next-step">Next</button>
      </div>

      <!-- Step 2 -->
      <div class="form-step">
        <div class="mb-3">
          <label for="email" class="form-label">Email</label>
          <input type="email" class="form-control" id="email" required>
        </div>
        <button type="button" class="btn btn-secondary prev-step">Previous</button>
        <button type="button" class="btn btn-primary next-step">Next</button>
      </div>

      <!-- Step 3 -->
      <div class="form-step">
        <div class="mb-3">
          <label for="password" class="form-label">Password</label>
          <input type="password" class="form-control" id="password" required>
        </div>
        <button type="button" class="btn btn-secondary prev-step">Previous</button>
        <button type="submit" class="btn btn-success">Submit</button>
      </div>
    </form>
  </div>
</body>

Explanation:

  • <form id="multiStepForm">: This is the container for our multi-step form. We’ll use JavaScript to handle the transitions between each step.
  • <div class="form-step">: Each form step is wrapped in a form-step div. Only one step will be visible at a time, and we will toggle between them.
  • Navigation Buttons: Each step has “Next” and “Previous” buttons, except for the first and last steps. These buttons will control the flow between form sections.

Each form step starts hidden, except the first step, which we marked with the active class. This will ensure only the first form section is visible when the page loads.

Setting Up Bootstrap 5 in WordPress Using Enqueue

If you’re working within a WordPress environment, it’s important to include Bootstrap 5 in the right way to ensure that it loads efficiently and does not conflict with other themes or plugins. The recommended approach is to enqueue Bootstrap 5’s CSS and JavaScript files using WordPress’s wp_enqueue_scripts function.

Step 1: Locate Your Theme’s functions.php File

The first step is to add the enqueue script inside your theme’s functions.php file. This file controls various functionalities of your WordPress theme, and it’s where you’ll add the necessary code to load Bootstrap 5.

  1. Access your WordPress installation either via your hosting provider’s file manager or using an FTP client.
  2. Navigate to the directory wp-content/themes/your-theme-name/.
  3. Open the functions.php file for editing.

Step 2: Enqueue Bootstrap 5 in functions.php

To enqueue the Bootstrap 5 CSS and JavaScript files, add the following code to your theme’s functions.php file:

function enqueue_bootstrap_5() {
// Enqueue Bootstrap 5 CSS
wp_enqueue_style('bootstrap-css', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css', array(), '5.3.0-alpha1');

// Enqueue Bootstrap 5 JS
wp_enqueue_script('bootstrap-js', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js', array('jquery'), '5.3.0-alpha1', true);
}
add_action('wp_enqueue_scripts', 'enqueue_bootstrap_5');

Explanation

  • wp_enqueue_style(): This function is used to load the Bootstrap 5 CSS file. It includes the file from the CDN, specifies that there are no dependencies (array()), and sets the version to 5.3.0-alpha1.
  • wp_enqueue_script(): This function loads Bootstrap 5’s JavaScript bundle (which includes Popper.js). It depends on jQuery, which WordPress includes by default. The final true parameter ensures that the script is loaded in the footer for better performance.
  • add_action('wp_enqueue_scripts', 'enqueue_bootstrap_5'): This tells WordPress to run the enqueue_bootstrap_5() function when it is adding scripts and styles to the page.

Step 3: Verify Bootstrap 5.3 Is Loaded

After adding the above code to your functions.php file, clear your site’s cache if necessary and refresh any page on the front end. Right-click on the page and select “Inspect” or “View Page Source.” Look for the Bootstrap 5 CSS and JavaScript files to ensure they’re being correctly enqueued.

Next, we’ll work on dividing the form into multiple steps and implementing the progress bar to visually represent the user’s journey.

This completes the introduction and the first section of the blog post. Let me know when you’re ready to move on to the next section!

Section 2: Structuring the Multi-Step Form

1. Create the Form Container and Basic Layout

With the basic structure in place, we’ll now focus on dividing the form into multiple steps. In a multi-step form, each section should be easy to navigate, with only one step visible at a time. Bootstrap’s grid system and utility classes allow us to structure and style the form effectively.

First, let’s ensure that each step is enclosed in its own container. We’ll use Bootstrap’s grid system to make the form responsive, ensuring that it looks good on both large screens and mobile devices.

step 1 - structure the mulit-step form

Here’s an updated structure, using Bootstrap’s grid:

<div class="container mt-5">
<h2 class="text-center mb-4">Multi-Step Form Example</h2>
<div class="row justify-content-center">
<div class="col-md-6">
<form id="multiStepForm">
<!-- Step 1 -->
<div class="form-step active">
<div class="mb-3">
<label for="firstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstName" required>
</div>
<div class="mb-3">
<label for="lastName" class="form-label">Last Name</label>
<input type="text" class="form-control" id="lastName" required>
</div>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 2 -->
<div class="form-step">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" required>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 3 -->
<div class="form-step">
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" required>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="submit" class="btn btn-success">Submit</button>
</div>
</form>
</div>
</div>
</div>

Explanation of the Layout

  • .container: Provides a responsive fixed-width container for the form.
  • .row and .col-md-6: Used to center the form and control its width, ensuring it’s responsive and takes up an appropriate amount of space on different devices.
  • form-step active: Only one step will be visible at a time, starting with the first step, which has the active class.

Now that we have the basic layout, let’s move on to adding a progress bar to indicate how far the user has progressed through the form.

2. Add the Bootstrap Progress Bar

step 2 - add the progress bar

A progress bar is a great way to visually show the user their progress through the form. Bootstrap 5 provides a progress bar component that is easy to customize. Here, we will create a progress bar that dynamically updates as the user moves through each step of the form.

Here’s how we can add the progress bar:

<div class="container mt-5">
<h2 class="text-center">Multi-Step Form Example</h2>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" style="width: 33%;" aria-valuenow="33" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<!-- Form content goes here -->
</div>

Explanation

  • .progress-bar: This is the Bootstrap component that we will use to create the visual progress indicator.
  • width: 33%;: Represents the percentage of the progress. We’ll dynamically change this value using JavaScript as the user moves between steps.
  • aria-valuenow: Reflects the current progress value in terms of percentage (starting with 33%).

In the next section, we’ll make this progress bar dynamic, updating its width based on the current step.

Section 3: Navigating Between Form Steps

To create a seamless multi-step form, we need to allow users to navigate between steps. This requires:

  1. Buttons to move forward and backward between steps.
  2. Logic to show the appropriate form step while hiding the others.
  3. Updating the progress bar based on the current step.

1. Add the “Next” and “Previous” Buttons

step 3 - add next and previous buttons

We already included Next and Previous buttons in our HTML structure. Let’s now write the JavaScript that will handle the navigation logic and update the form based on which step the user is on.

Here’s the JavaScript for navigating between steps:

const steps = document.querySelectorAll(".form-step");
const nextBtns = document.querySelectorAll(".next-step");
const prevBtns = document.querySelectorAll(".prev-step");
const progressBar = document.querySelector(".progress-bar");

let currentStep = 0;

nextBtns.forEach((button) => {
button.addEventListener("click", () => {
steps[currentStep].classList.remove("active");
currentStep++;
steps[currentStep].classList.add("active");
updateProgressBar();
});
});

prevBtns.forEach((button) => {
button.addEventListener("click", () => {
steps[currentStep].classList.remove("active");
currentStep--;
steps[currentStep].classList.add("active");
updateProgressBar();
});
});

function updateProgressBar() {
const progress = ((currentStep + 1) / steps.length) * 100;
progressBar.style.width = `${progress}%`;
progressBar.setAttribute("aria-valuenow", progress);
}

Explanation

  • Selecting the elements: We select all steps (.form-step), next buttons (.next-step), previous buttons (.prev-step), and the progress bar (.progress-bar).
  • Tracking current step: The variable currentStep tracks which form step is active. It starts at 0 (the first step).
  • Next and previous buttons: Clicking the Next button hides the current step and shows the next one, while the Previous button does the opposite.
  • Updating progress bar: The function updateProgressBar() calculates the percentage of progress based on the current step and updates the width of the progress bar accordingly.

2. Ensure Form Validation for Each Step

step 4 - add form validation

Before allowing the user to proceed to the next step, it’s important to validate the inputs of the current step to ensure they’re filled out correctly. Bootstrap 5’s built-in form validation classes make this easy.

Here’s how you can add validation to ensure users cannot move to the next step unless all required fields are filled out:

nextBtns.forEach((button) => {
button.addEventListener("click", (e) => {
const currentInputs = steps[currentStep].querySelectorAll("input");
let valid = true;

currentInputs.forEach((input) => {
if (!input.checkValidity()) {
input.classList.add("is-invalid");
valid = false;
} else {
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});

if (valid) {
steps[currentStep].classList.remove("active");
currentStep++;
steps[currentStep].classList.add("active");
updateProgressBar();
}
});
});

Explanation

  • Form validation check: We loop through the current step’s inputs and check if they are valid using HTML5’s checkValidity() method.
  • Adding validation feedback: Bootstrap 5’s .is-invalid and .is-valid classes are added to provide real-time feedback to the user.
  • Prevent navigation if invalid: If any input is invalid, the user cannot move to the next step.

At this point, we have successfully implemented the basic structure of the multi-step form with working Next and Previous buttons. We’ve also integrated a progress bar that dynamically updates based on the user’s progress through the form. Additionally, we’ve included form validation to ensure the user enters correct data before proceeding to the next step.

In the next section, we’ll refine the user experience by adding smooth transitions and handling form submission for the final step.

Section 4: Updating the Progress Bar Dynamically

Now that we have a functional multi-step form with navigation buttons, it’s time to add the logic that dynamically updates the progress bar as the user moves through the form. This visual feedback helps users see how much they’ve completed and how much is left, which can motivate them to complete the form.

1. Track User Progress Through the Multi-Step Form

The progress bar is an essential part of a multi-step form, as it provides users with a visual indicator of how far they have progressed. To achieve this, we need to update the width of the progress bar each time the user clicks the “Next” or “Previous” button.

We’ve already included the progress bar HTML in Section 2, so now let’s write the JavaScript code that will update its width dynamically based on the user’s current step.

Here’s the code for updating the progress bar:

const progressBar = document.querySelector(".progress-bar");

// Function to update progress bar based on the current step
function updateProgressBar() {
const progress = ((currentStep + 1) / steps.length) * 100;
progressBar.style.width = `${progress}%`;
progressBar.setAttribute("aria-valuenow", progress);
}

Explanation

  • progressBar.style.width: This line dynamically updates the progress bar’s width based on the current step. The percentage is calculated by dividing the current step by the total number of steps and multiplying by 100.
  • aria-valuenow: This attribute is updated to reflect the progress percentage, improving accessibility for screen readers.

2. Implement the Progress Bar Logic in the Navigation Functions

Now that we have the updateProgressBar() function, we need to ensure it is called each time the user navigates to a new step (when they click either “Next” or “Previous”).

Here’s how to integrate it with the existing navigation logic from Section 3:

nextBtns.forEach((button) => {
button.addEventListener("click", () => {
const currentInputs = steps[currentStep].querySelectorAll("input");
let valid = true;

// Check form validation before moving to the next step
currentInputs.forEach((input) => {
if (!input.checkValidity()) {
input.classList.add("is-invalid");
valid = false;
} else {
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});

// If inputs are valid, proceed to the next step and update progress bar
if (valid) {
steps[currentStep].classList.remove("active");
currentStep++;
steps[currentStep].classList.add("active");
updateProgressBar();
}
});
});

prevBtns.forEach((button) => {
button.addEventListener("click", () => {
steps[currentStep].classList.remove("active");
currentStep--;
steps[currentStep].classList.add("active");
updateProgressBar();
});
});

Explanation

  • Progress bar update: Each time the user clicks the “Next” or “Previous” button, we call the updateProgressBar() function to update the progress percentage.
  • Next and previous buttons: When the user navigates between steps, the current step is updated, and the aria-valuenow and width of the progress bar change accordingly.

How the Multi-Step Form Progress Bar Works

Let’s walk through how the progress bar updates as the user navigates through the steps of the form.

  1. On Page Load:
    • The user sees the first step, and the progress bar is set to 33% (assuming there are three steps). This is calculated as (1/3) * 100 = 33%.
  2. When the User Clicks “Next”:
    • The current step changes to the second step, and the progress bar updates to 66%. This is calculated as (2/3) * 100 = 66%.
  3. On the Final Step:
    • When the user reaches the third step, the progress bar reaches 100%, indicating that the form is ready to be submitted.

Final Code for the Progress Bar and Form Navigation

Here’s the full code for the multi-step form with the dynamically updating progress bar and validation:

<div class="container mt-5">
<h2 class="text-center">Multi-Step Form Example</h2>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" style="width: 33%;" aria-valuenow="33" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<form id="multiStepForm">
<!-- Step 1 -->
<div class="form-step active">
<div class="mb-3">
<label for="firstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstName" required>
</div>
<div class="mb-3">
<label for="lastName" class="form-label">Last Name</label>
<input type="text" class="form-control" id="lastName" required>
</div>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 2 -->
<div class="form-step">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" required>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 3 -->
<div class="form-step">
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" required>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="submit" class="btn btn-success">Submit</button>
</div>
</form>
</div>
</div>
</div>

<script>
const steps = document.querySelectorAll(".form-step");
const nextBtns = document.querySelectorAll(".next-step");
const prevBtns = document.querySelectorAll(".prev-step");
const progressBar = document.querySelector(".progress-bar");
let currentStep = 0;

nextBtns.forEach((button) => {
button.addEventListener("click", () => {
const currentInputs = steps[currentStep].querySelectorAll("input");
let valid = true;

currentInputs.forEach((input) => {
if (!input.checkValidity()) {
input.classList.add("is-invalid");
valid = false;
} else {
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});

if (valid) {
steps[currentStep].classList.remove("active");
currentStep++;
steps[currentStep].classList.add("active");
updateProgressBar();
}
});
});

prevBtns.forEach((button) => {
button.addEventListener("click", () => {
steps[currentStep].classList.remove("active");
currentStep--;
steps[currentStep].classList.add("active");
updateProgressBar();
});
});

function updateProgressBar() {
const progress = ((currentStep + 1) / steps.length) * 100;
progressBar.style.width = `${progress}%`;
progressBar.setAttribute("aria-valuenow", progress);
}
</script>

By the end of this section, you’ve successfully integrated a dynamically updating progress bar into your multi-step form. Each time the user advances or goes back a step, the progress bar reflects the percentage completed, providing them with a clear visual indicator of their progress. This enhances the user experience and makes the form more engaging.

Next, we’ll focus on adding smooth transitions between steps and handling form submission for the final step!

Section 5: Adding Smooth Transitions Between Steps

To further improve the user experience of your multi-step form, adding smooth transitions between steps will make the form feel more interactive and polished. Instead of abruptly switching from one form step to the next, you can use simple CSS transitions to create a smooth fade effect between the steps.

In this section, we will:

  1. Apply smooth fade-in and fade-out transitions when moving between steps.
  2. Implement transitions using CSS and JavaScript, while ensuring no layout issues or glitches occur during the transition.

Enhance User Experience with Transitions

Transitions between form steps provide visual feedback to users, making the form feel more dynamic and engaging. A simple fade effect can improve the user’s perception of the form, making it feel more polished. However, to avoid layout shifting or animation glitches, it’s important to handle the form steps in a way that ensures only the active step is displayed, while the others are hidden.

Step 1: Use display: none and display: block

We will use display: none to hide inactive steps and display: block to show the current active step. This ensures that the steps won’t stack on top of each other or cause any visual issues during the transition.

Here’s the updated CSS to handle transitions between steps:

.form-step {
display: none;
opacity: 0;
transition: opacity 0.5s ease-in-out;
}

.form-step.active {
display: block;
opacity: 1;
transition: opacity 0.5s ease-in-out;
}

.progress-bar {
transition: width 0.5s ease-in-out;
}

Explanation

  • display: none: This hides the inactive steps, so they don’t occupy any space in the document.
  • display: block: This shows only the active step, making it visible to the user.
  • Smooth opacity transitions: By applying opacity transitions, the steps will fade in and out smoothly as the user moves from one step to the next.

Step 2: Modifying the JavaScript to Show and Hide Steps

The JavaScript logic for handling the transitions remains largely the same. When the user clicks the Next or Previous buttons, we need to show the next step by adding the active class (which sets display: block), and hide the current step by removing the active class (which sets display: none).

Here’s the JavaScript for navigating between steps:

const steps = document.querySelectorAll(".form-step");
const nextBtns = document.querySelectorAll(".next-step");
const prevBtns = document.querySelectorAll(".prev-step");
const progressBar = document.querySelector(".progress-bar");

let currentStep = 0;

// Next Button Event Listeners
nextBtns.forEach((button) => {
button.addEventListener("click", () => {
const currentInputs = steps[currentStep].querySelectorAll("input, select");
let valid = true;

currentInputs.forEach((input) => {
if (!input.checkValidity()) {
input.classList.add("is-invalid");
valid = false;
} else {
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});

if (valid) {
steps[currentStep].classList.remove("active");
currentStep++;

// If we're on the final step, populate the review fields
if (currentStep === steps.length - 1) {
document.getElementById('reviewFirstName').textContent = document.getElementById('firstName').value;
document.getElementById('reviewLastName').textContent = document.getElementById('lastName').value;
document.getElementById('reviewEmail').textContent = document.getElementById('email').value;
}

steps[currentStep].classList.add("active");
updateProgressBar();
}
});
});

// Previous Button Event Listeners
prevBtns.forEach((button) => {
button.addEventListener("click", () => {
steps[currentStep].classList.remove("active");
currentStep--;
steps[currentStep].classList.add("active");
updateProgressBar();
});
});

// Update Progress Bar
function updateProgressBar() {
const progress = ((currentStep + 1) / steps.length) * 100;
progressBar.style.width = `${progress}%`;
progressBar.setAttribute("aria-valuenow", progress);
}

Explanation

  • The Next and Previous buttons add or remove the active class to control which step is displayed.
  • When a step becomes active, the CSS sets display: block and fades in the step using the opacity transition.
  • The progress bar is updated dynamically to reflect how far the user has progressed through the form.

Test Transitions for Smooth Experience

Once you’ve applied the changes, you can test the form to ensure that the transitions between steps are smooth and that no layout shifts or animation glitches occur. The steps should appear in the same space, and the fade effect will make the form feel more responsive and polished.

By using display: none for inactive steps and display: block for the active step, we ensure that the multi-step form transitions smoothly without causing layout shifts or animation glitches. This method also keeps the steps neatly contained within the same space, providing a polished user experience.

Now that the transitions are in place, users can navigate the form with ease, and the smooth fade-in effect adds a professional touch to the interaction.

Section 6: Submitting the Form and Handling the Final Step

Now that the multi-step form is fully functional with smooth transitions and a dynamic progress bar, it’s time to focus on the final step: form submission. In this section, we will ensure that the data entered across all steps is properly validated and handled, giving users the ability to review their inputs before submitting the form.

We’ll walk through how to:

  1. Add a review and confirmation step.
  2. Handle form submission with JavaScript or AJAX to send data without reloading the page.
  3. Provide feedback to users upon successful submission or error.

1. Form Review and Confirmation Step

Before the user submits the form, it’s often helpful to provide a final review step where they can check all of their inputted information. This reduces errors and gives users a chance to correct any mistakes.

Step 1: Creating the Review Step in HTML

We’ll add a review section in our form as the final step, summarizing the user’s inputs from the previous steps. Modify your HTML like this:

<!-- Step 3: Review and Submit -->
<div class="form-step">
<h4>Review Your Information</h4>
<div class="review-info">
<p><strong>First Name:</strong> <span id="reviewFirstName"></span></p>
<p><strong>Last Name:</strong> <span id="reviewLastName"></span></p>
<p><strong>Email:</strong> <span id="reviewEmail"></span></p>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="submit" class="btn btn-success">Submit</button>
</div>

Step 2: Populating the Review Fields with JavaScript

When the user reaches the review step, we’ll use JavaScript to populate the reviewFirstName, reviewLastName, and reviewEmail fields with the data they entered in the form. Here’s the JavaScript to handle this:

const reviewFirstName = document.getElementById('reviewFirstName');
const reviewLastName = document.getElementById('reviewLastName');
const reviewEmail = document.getElementById('reviewEmail');

nextBtns.forEach((button) => {
button.addEventListener("click", () => {
const currentInputs = steps[currentStep].querySelectorAll("input");
let valid = true;

currentInputs.forEach((input) => {
if (!input.checkValidity()) {
input.classList.add("is-invalid");
valid = false;
} else {
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});

if (valid) {
steps[currentStep].classList.remove("active");
currentStep++;

// If we're on the final step, populate the review fields
if (currentStep === steps.length - 1) {
reviewFirstName.textContent = document.getElementById('firstName').value;
reviewLastName.textContent = document.getElementById('lastName').value;
reviewEmail.textContent = document.getElementById('email').value;
}

steps[currentStep].classList.add("active");
updateProgressBar();
}
});
});

Explanation

  • Populating the review step: When the user reaches the last step, we update the content of the reviewFirstName, reviewLastName, and reviewEmail fields with the values they entered.
  • Checking validation: Before moving to the review step, we continue to validate the form inputs.

2. Submit the Form

Now that the user has reviewed their inputs, they can submit the form. You can either submit the form traditionally (with a page reload) or use AJAX to submit it asynchronously, allowing the page to remain intact while processing the data in the background.

Option 1: Standard Form Submission

This is the simplest approach, where we let the browser handle the form submission and redirect the user after the form is submitted.

Ensure your form has a method and action attribute to specify how the data should be sent and where it should go:

<form id="multiStepForm" method="POST" action="/submit-form">
<!-- Form steps here -->
</form>

When the user clicks the submit button, the browser will send the data to the server for processing.

Option 2: AJAX Form Submission (No Page Reload)

For a better user experience, you can submit the form using AJAX, which allows you to send the form data to the server without refreshing the page. Here’s how you can implement AJAX submission:

First, add an event listener to prevent the form’s default submission behavior and instead handle it with JavaScript:

const form = document.getElementById('multiStepForm');

form.addEventListener('submit', function (event) {
event.preventDefault(); // Prevent default form submission

// Gather form data
const formData = new FormData(form);

// Send form data via AJAX (using Fetch API)
fetch('/submit-form', {
method: 'POST',
body: formData,
})
.then(response => {
if (response.ok) {
// Handle success, such as displaying a success message or redirecting
alert('Form submitted successfully!');
} else {
// Handle errors
alert('There was a problem submitting the form.');
}
})
.catch(error => {
// Handle network errors or unexpected issues
alert('An error occurred. Please try again.');
});
});

Explanation

  • event.preventDefault(): Prevents the default form submission so we can handle it via AJAX.
  • FormData(): Collects the form data to send to the server.
  • fetch(): Sends the form data to the server using the Fetch API, which allows us to submit the data without reloading the page.
  • Error handling: We provide feedback to the user in case the form submission fails.

Providing User Feedback

Once the form is successfully submitted, it’s important to provide feedback to the user. This could be a success message, a redirect to a thank-you page, or some other visual confirmation that their data has been received.

Example of Success Message

After successfully submitting the form via AJAX, you can display a success message like this:

.then(response => {
if (response.ok) {
document.getElementById('multiStepForm').innerHTML = `
<div class="alert alert-success">
<h4>Thank you for your submission!</h4>
<p>Your form has been successfully submitted.</p>
</div>
`;
}
})

Explanation

  • This code replaces the form with a success message after the form is submitted. You could also redirect the user to a different page using window.location.href if that’s preferred.

Error Handling

If the form submission fails, it’s crucial to inform the user about the issue and guide them on how to fix it. This could be due to network issues, server errors, or incorrect form inputs.

You can display an error message like this:

.catch(error => {
document.getElementById('multiStepForm').innerHTML = `
<div class="alert alert-danger">
<h4>Submission Failed</h4>
<p>There was an error submitting your form. Please try again later.</p>
</div>
`;
});

Additional Validation for the Entire Form

Even though we’re validating each step before the user moves forward, you can add an additional layer of validation on form submission to ensure that all data is correct before sending it to the server. This can be done by re-validating all the inputs in the form on submission.

form.addEventListener('submit', function (event) {
const allInputs = form.querySelectorAll('input');
let valid = true;

allInputs.forEach(input => {
if (!input.checkValidity()) {
input.classList.add('is-invalid');
valid = false;
}
});

if (!valid) {
event.preventDefault(); // Stop submission if any inputs are invalid
alert('Please correct the errors in the form before submitting.');
}
});

At this point, you have a fully functional multi-step form that allows users to review their inputs before submitting and handles form submission either through a standard method or via AJAX for a more modern experience. You also have robust form validation in place and provide feedback to users in case of successful submission or errors.

This marks the final major section of our tutorial. We’ve built a dynamic, interactive, and user-friendly multi-step form using Bootstrap 5, JavaScript, and AJAX.

Feel free to customize the form further based on your project needs, whether by adding more form steps, refining the design, or integrating advanced features like conditional logic for form fields.

Section 7: Bonus Features for Advanced Customization

Now that we’ve built a fully functional multi-step form with Bootstrap 5, dynamic transitions, and form submission handling, we can explore some advanced customization options. These enhancements will further improve the form’s functionality and user experience, making it more flexible and interactive for different use cases.

In this section, we’ll cover:

  1. Adding conditional steps to display specific form sections based on user input.
  2. Implementing accessibility features to ensure the form is usable by people with disabilities.

Adding Conditional Steps

In some cases, you may want to show or hide certain steps of the form based on the user’s input. For example, if the user selects “Business” in a drop-down menu, additional fields related to business details may appear. This type of conditional logic can be useful for tailoring the form to the user’s needs.

Step 1: Modify the HTML to Include a Conditional Section

Let’s assume we have a step where the user selects their “user type” (Individual or Business). If the user selects “Business”, an additional step will appear to collect business-related information.

Here’s the updated HTML for this conditional logic:

<!-- Step 2: User Type Selection -->
<div class="form-step">
<div class="mb-3">
<label for="userType" class="form-label">Are you an individual or a business?</label>
<select id="userType" class="form-select" required>
<option value="">Select...</option>
<option value="individual">Individual</option>
<option value="business">Business</option>
</select>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 3: Business Details (Conditional Step) -->
<div class="form-step conditional-step">
<h4>Business Details</h4>
<div class="mb-3">
<label for="businessName" class="form-label">Business Name</label>
<input type="text" class="form-control" id="businessName">
</div>
<div class="mb-3">
<label for="businessEmail" class="form-label">Business Email</label>
<input type="email" class="form-control" id="businessEmail">
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

Step 2: JavaScript to Show/Hide Conditional Step

We’ll use JavaScript to detect the user’s selection and conditionally show or hide the Business Details step.

Here’s the JavaScript to handle this logic:

const userTypeSelect = document.getElementById('userType');
const businessStep = document.querySelector('.conditional-step');

// Listen for changes in the user type dropdown
userTypeSelect.addEventListener('change', function () {
if (userTypeSelect.value === 'business') {
businessStep.style.display = 'block'; // Show business details step
} else {
businessStep.style.display = 'none'; // Hide business details step
}
});

// Ensure the business step is hidden initially
businessStep.style.display = 'none';

Explanation

  • change event listener: This listens for changes to the user’s selection in the dropdown menu. If the user selects “Business”, the business details step becomes visible; otherwise, it remains hidden.
  • businessStep.style.display = 'none': Hides the conditional step initially, so it only appears when the correct condition is met.

This allows the form to adapt dynamically based on user input, showing or hiding certain sections as needed.

Enhance Accessibility

Ensuring that your multi-step form is accessible to all users, including those with disabilities, is crucial for creating an inclusive user experience. Here are some ways to improve accessibility:

Step 1: Use aria-* Attributes for Accessibility

We can add aria-* attributes to help users who rely on screen readers understand the form’s structure and progress.

Here’s how you can enhance the progress bar and form fields for better accessibility:

  1. Progress Bar Accessibility:
<div class="progress mb-4" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="33" aria-labelledby="form-progress">
<div class="progress-bar" id="form-progress" style="width: 33%;"></div>
</div>
  • role="progressbar": Indicates that the element is a progress bar.
  • aria-valuenow="33": Dynamically updates with the current percentage of the progress.
  • aria-labelledby="form-progress": Associates the progress bar with an element that describes it, improving screen reader support.
  1. Form Field Labels and aria-describedby:

Ensure that every form field has an associated label and use aria-describedby to provide additional context or help text where necessary.

For example:

<div class="mb-3">
<label for="firstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstName" aria-describedby="firstNameHelp" required>
<div id="firstNameHelp" class="form-text">Enter your first name as it appears on official documents.</div>
</div>
  • aria-describedby="firstNameHelp": Links the form field to the help text below it, so screen readers can read the help text when the user focuses on the input field.

Step 2: Keyboard Navigation Support

Users with disabilities often rely on keyboard navigation. To ensure the form is fully navigable using just a keyboard:

  • Use tabindex to control the tab order, ensuring logical navigation between form fields.
  • Ensure that all interactive elements (buttons, form fields) are focusable using the tab key.

Additionally, the following best practices will ensure the form is usable with a keyboard:

  • Make sure buttons are reachable via tab, and that pressing Enter or Space activates them.
  • Implement focus outlines so users can visually track their location in the form.

In this section, we explored advanced customization options to further enhance the form’s flexibility and user experience:

  1. Conditional steps make the form dynamic, adjusting the fields shown to the user based on their input, which can simplify the form for users by only showing relevant sections.
  2. Accessibility improvements using aria-* attributes, focus management, and screen reader support ensure that the form is usable by people with disabilities and those relying on keyboard navigation.

By incorporating these enhancements, your multi-step form becomes more versatile, adaptable to a wider audience, and more user-friendly, making it a powerful tool for collecting information in a variety of contexts.

Conclusion

In this tutorial, we walked through the process of creating a fully functional multi-step form using Bootstrap 5. We started with the basics of setting up the form structure, added smooth transitions, and implemented a progress bar to provide users with visual feedback as they navigate through the form. We also explored more advanced features such as conditional steps and improving the form’s accessibility.

By using Bootstrap 5’s grid system, progress bars, and validation utilities, we created a responsive, dynamic form that is easy to use and enhances the user experience. Additionally, we ensured that the form can be adapted to more complex use cases, such as dynamically adjusting form steps based on user input and supporting AJAX submissions.

Whether you are creating simple multi-step forms or more complex workflows, this tutorial provides a foundation that you can build upon to suit your project’s needs. Below, you will find the full code (HTML, CSS, and JavaScript) that puts everything together.

Full Code for Multi-Step Form

HTML: Multi-Step Form Structure

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-Step Form</title>
<!-- Bootstrap 5 CSS CDN -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Link to Custom CSS (Optional) -->
<link rel="stylesheet" href="styles.css">
</head>
<body>

<div class="container mt-5">
<h2 class="text-center">Multi-Step Form Example</h2>

<!-- Progress Bar -->
<div class="row justify-content-center">
<div class="col-md-6">
<div class="progress mb-4" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="25" aria-labelledby="form-progress">
<div class="progress-bar" id="form-progress" style="width: 25%;"></div>
</div>
</div>
</div>

<div class="row justify-content-center">
<div class="col-md-6">
<!-- Multi-Step Form -->
<form id="multiStepForm">

<!-- Step 1: Personal Details -->
<div class="form-step active">
<div class="mb-3">
<label for="firstName" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstName" required aria-describedby="firstNameHelp">
<div id="firstNameHelp" class="form-text">Enter your first name.</div>
</div>
<div class="mb-3">
<label for="lastName" class="form-label">Last Name</label>
<input type="text" class="form-control" id="lastName" required>
</div>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 2: User Type Selection -->
<div class="form-step">
<div class="mb-3">
<label for="userType" class="form-label">Are you an individual or a business?</label>
<select id="userType" class="form-select" required>
<option value="">Select...</option>
<option value="individual">Individual</option>
<option value="business">Business</option>
</select>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 3: Business Details -->
<div class="form-step">
<h4>Business Details</h4>
<div class="mb-3">
<label for="businessName" class="form-label">Business Name</label>
<input type="text" class="form-control" id="businessName">
</div>
<div class="mb-3">
<label for="businessEmail" class="form-label">Business Email</label>
<input type="email" class="form-control" id="businessEmail">
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="button" class="btn btn-primary next-step">Next</button>
</div>

<!-- Step 4: Review and Submit -->
<div class="form-step">
<h4>Review Your Information</h4>
<div class="review-info">
<p><strong>First Name:</strong> <span id="reviewFirstName"></span></p>
<p><strong>Last Name:</strong> <span id="reviewLastName"></span></p>
<p><strong>Email:</strong> <span id="reviewEmail"></span></p>
</div>
<button type="button" class="btn btn-secondary prev-step">Previous</button>
<button type="submit" class="btn btn-success">Submit</button>
</div>

</form>
</div>
</div>
</div>

<!-- Bootstrap 5 JavaScript CDN -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<!-- Link to Custom JavaScript -->
<script src="script.js"></script>

</body>
</html>

CSS: Styling for Multi-Step Form (styles.css)

.form-step {
opacity: 0;
visibility: hidden;
transition: opacity 0.5s ease-in-out, visibility 0.5s ease-in-out;
}

.form-step.active {
opacity: 1;
visibility: visible;
transition: opacity 0.5s ease-in-out, visibility 0.5s ease-in-out;
}

.progress-bar {
transition: width 0.5s ease-in-out;
}

This CSS handles the fade transitions between form steps and adds smooth transitions to the progress bar width.

JavaScript: Form Functionality (script.js)

The following JavaScript contains additional dataLayer events for sending data directly to Google Tag Manager for each form step and an event when a user submits the form.

const steps = document.querySelectorAll(".form-step");
const nextBtns = document.querySelectorAll(".next-step");
const prevBtns = document.querySelectorAll(".prev-step");
const progressBar = document.querySelector(".progress-bar");

let currentStep = 0;

// Initialize dataLayer if not already initialized
window.dataLayer = window.dataLayer || [];

// Function to update progress bar
function updateProgressBar() {
const progress = ((currentStep + 1) / steps.length) * 100;
progressBar.style.width = `${progress}%`;
progressBar.setAttribute("aria-valuenow", progress);
}

// Function to show the current step and send dataLayer event
function showCurrentStep() {
steps.forEach((step, index) => {
if (index === currentStep) {
step.classList.add("active");
} else {
step.classList.remove("active");
}
});

// Fire dataLayer event for each step
window.dataLayer.push({
'event': `form_step_${currentStep + 1}`
});

updateProgressBar();
}

// Initialize first step visibility
showCurrentStep();

// Next button event listeners
nextBtns.forEach((button) => {
button.addEventListener("click", () => {
const currentInputs = steps[currentStep].querySelectorAll("input, select");
let valid = true;

// Validate the current inputs
currentInputs.forEach((input) => {
if (!input.checkValidity()) {
input.classList.add("is-invalid");
valid = false;
} else {
input.classList.remove("is-invalid");
input.classList.add("is-valid");
}
});

if (valid) {
steps[currentStep].classList.remove("active");
currentStep++;

// Populate review fields if on the final step
if (currentStep === steps.length - 1) {
document.getElementById('reviewFirstName').textContent = document.getElementById('firstName').value;
document.getElementById('reviewLastName').textContent = document.getElementById('lastName').value;
document.getElementById('reviewEmail').textContent = document.getElementById('businessEmail').value || document.getElementById('email').value;
}

showCurrentStep();
}
});
});

// Previous button event listeners
prevBtns.forEach((button) => {
button.addEventListener("click", () => {
currentStep--;
showCurrentStep();
});
});

// Add event listener for form submission to fire the generate_lead event
document.getElementById("multiStepForm").addEventListener("submit", function (e) {
e.preventDefault(); // Prevent the default form submission for this example

// Fire generate_lead event in the dataLayer
window.dataLayer.push({
'event': 'generate_lead'
});

// Continue with form submission logic or AJAX call, if needed
// Example: alert('Form submitted successfully!');
});

Key Explanation

  • Form Step Navigation: This JavaScript handles the “Next” and “Previous” buttons to switch between form steps.
  • Form Validation: Before advancing to the next step, the input fields are validated using HTML5 form validation (checkValidity()).
  • Dynamic Progress Bar: The progress bar updates its width based on the current step, giving users a visual indicator of their progress.
  • Review Information on Final Step: The data entered in the previous steps (First Name, Last Name, and Email) is displayed on the final step for review.

Join 1,000s of Business Owners, Marketers, and Agencies with FREE Marketing Tips.