Originally posted on my blog
A stepper or multi-step form is a handy feature to have when dealing with long-forms. It enhances your user experience with a more user-friendly form format. In this tutorial, we will be creating a stepper form using HTML, CSS, and JavaScript.
You can check it live on Codepen : Stepper Form
Let's get started!
Markup
As you can see, the HTML file is relatively simple.
<main>
<div class="stepper">
<div class="step--1 step-active">Step 1</div>
<div class="step--2">Step 2</div>
<div class="step--3">Step 3</div>
<div class="step--4">Finish</div>
</div>
<form class="form form-active">
<div class="form--header-container">
<h1 class="form--header-title">
Personal Info
</h1>
<p class="form--header-text">
Tell us more about you.
</p>
</div>
<input type="text" placeholder="Name" />
<input type="text" placeholder="Email" />
<input type="text" placeholder="Password" />
<button class="form__btn" id="btn-1">Next</button>
</form>
<form class="form">
<div class="form--header-container">
<h1 class="form--header-title">
Company Info
</h1>
<p class="form--header-text">
Tell us more about your company.
</p>
</div>
<input type="text" placeholder="Company Name" />
<input type="text" placeholder="Job title" />
<input type="text" placeholder="Location" />
<button class="form__btn" id="btn-2-prev">Previous</button>
<button class="form__btn" id="btn-2-next">Next</button>
</form>
<form class="form">
<div class="form--header-container">
<h1 class="form--header-title">
Social account
</h1>
<p class="form--header-text">
Tell us more about your social account.
</p>
</div>
<input type="text" placeholder="Linkedin" />
<input type="text" placeholder="Twitter" />
<input type="text" placeholder="Github" />
<button class="form__btn" id="btn-3">Submit</button>
</form>
<div class="form--message"></div>
</main>
Besides the main
tag, we also define a div
that holds the stepper element. Then, we use three forms
with different buttons id
which will soon make the stepper effect with the help of JavaScript.
With this in place, we can now style the project with CSS.
Styling
Here, we begin with some resets and then set the font-family
and background-color
properties for the body
tag.
@import url('https://fonts.googleapis.com/css?family=Nunito&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #f5f6f7;
font-family: 'Nunito', sans-serif;
}
main {
height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: relative;
}
Next, we use the flex
value on the main
tag to center the element relative to the body
tag.
.stepper {
width: 20rem;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 5%;
}
.step--1,
.step--2,
.step--3,
.step--4 {
width: 5rem;
padding: 0.5rem 0;
background: #fff;
color: #666;
text-align: center;
}
.step--1,
.step--2,
.step--3 {
border-right: 1px solid #666;
}
For the Stepper elements, we rely on CSS flexbox to align them horizontally and then use their class names to add the style.
.form {
background: #fff;
text-align: center;
position: absolute;
width: 25rem;
box-shadow: 0.2rem 0.2rem 0.5rem rgba(51, 51, 51, 0.2);
display: none;
border-radius: 1rem;
overflow: hidden;
}
.form--header-container {
background: linear-gradient(to right, rgb(51, 51, 51), #919191);
color: #fff;
height: 6rem;
padding: 1rem 0;
margin-bottom: 2rem;
}
.form--header-title {
font-size: 1.4rem;
}
.form--header-text {
padding: 0.5rem 0;
}
input[type='text'] {
padding: 0.8rem;
margin: auto;
margin-top: 0.5rem;
width: 20rem;
display: block;
border-radius: 0.5rem;
outline: none;
border: 1px solid #bdbdbb;
}
.form__btn {
background: #333;
color: #fff;
outline: none;
border: none;
padding: 0.5rem 0.7rem;
width: 7rem;
margin: 1rem auto;
border-radius: 0.9rem;
text-transform: uppercase;
font-weight: 700;
cursor: pointer;
}
.form--message-text {
width: 25rem;
background: #fff;
color: #444;
padding: 2rem 1rem;
text-align: center;
font-size: 1.4rem;
box-shadow: 0.2rem 0.2rem 0.5rem rgba(51, 51, 51, 0.2);
animation: fadeIn 0.8s;
border-radius: 1rem;
}
In the beginning, we will hide all three forms. Only the form that contains the class active class
will be shown.
In the form--header-container
class, we use linear-gradient
to style the form header.
Next, in the form--message-text
class, we add the animation
property to have a fade-in effect when the form is submitted successfully.
.form-active {
z-index: 1000;
display: block;
}
.form-active-animate {
animation: moveRight 1s;
}
.form-inactive {
display: block;
animation: moveLeft 1s;
}
.step-active {
background: #666;
color: #fff;
border: 1px solid #666;
}
We use the form-active
class to show the current form. And also the property z-index
to put the form on top of other elements.
Next, we use the form-active-animate
class to make a nice animation entrance from the left to the right. We also have the class name form-inactive
that helps hide the previous form.
@keyframes moveRight {
0% {
transform: translateX(-27rem) scale(0.9);
opacity: 0;
}
100% {
transform: translateX(0rem) scale(1);
opacity: 1;
}
}
@keyframes moveLeft {
0% {
transform: translateX(0rem) scale(1);
opacity: 1;
}
100% {
transform: translateX(27rem) scale(0.9);
opacity: 0;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
As you can see here, we rely on keyframes
to make the animation.
The first animation, moveRight
will move the element from left to right using the property transform
.
For the second animation, this is relatively the same process, except the element will move more on the right side.
The last animation, fadeIn
, will start the fade-in effect when the element shows.
JavaScript
As you can see here, we listen to the click event and then use the gotoNextForm
function to handle it.
const formBtn1 = document.querySelector('#btn-1');
const formBtnPrev2 = document.querySelector('#btn-2-prev');
const formBtnNext2 = document.querySelector('#btn-2-next');
const formBtn3 = document.querySelector('#btn-3');
To interact with the DOM, we need to select all form buttons using the querySelector
method.
// Button listener of form 1
formBtn1.addEventListener('click', function(e) {
gotoNextForm(formBtn1, formBtnNext2, 1, 2);
e.preventDefault();
});
// Next button listener of form 2
formBtnNext2.addEventListener('click', function(e) {
gotoNextForm(formBtnNext2, formBtn3, 2, 3);
e.preventDefault();
});
// Previous button listener of form 2
formBtnPrev2.addEventListener('click', function(e) {
gotoNextForm(formBtnNext2, formBtn1, 2, 1);
e.preventDefault();
});
// Button listener of form 3
formBtn3.addEventListener('click', function(e) {
document.querySelector(`.step--3`).classList.remove('step-active');
document.querySelector(`.step--4`).classList.add('step-active');
formBtn3.parentElement.style.display = 'none';
document.querySelector('.form--message').innerHTML = `
<h1 class="form--message-text">Your account is successfully created </h1>
`;
e.preventDefault();
});
Here, we start by passing in the form ids as parameters and then use the method preventDefault()
on the event to prevent the page reload.
The listener formBtn3
is a bit different because we have to show a message to the user. That's why we use innerHTML
to append the content.
const gotoNextForm = (prev, next, stepPrev, stepNext) => {
// Get form through the button
const prevForm = prev.parentElement;
const nextForm = next.parentElement;
const nextStep = document.querySelector(`.step--${stepNext}`);
const prevStep = document.querySelector(`.step--${stepPrev}`);
// Add active/inactive classes to both previous and next form
nextForm.classList.add('form-active');
nextForm.classList.add('form-active-animate');
prevForm.classList.add('form-inactive');
// Change the active step element
prevStep.classList.remove('step-active');
nextStep.classList.add('step-active');
// Remove active/inactive classes to both previous an next form
setTimeout(() => {
prevForm.classList.remove('form-active');
prevForm.classList.remove('form-inactive');
nextForm.classList.remove('form-active-animate');
}, 1000);
};
Here, we traverse the DOM using the parentElement
property on both prevForm and nextForm variables to select the form
element.
Next, we use the variables to select the form steps from the stepper element.
After that, we add the classes form-active
and form-active-animate
to the next form element to have a nice animation effect.
Next, we remove form-active
, form-inactive
and form-active-animate
classes from the forms after 1 second using setTimeout().
Great! We are done building an Awesome Stepper Form with HTML, CSS, and JavaScript.
You can follow me on Twitter to get notified when a new article is published.
Thanks for reading!
Top comments (8)
Ça marche bro en fait il y'avait un petit conflit entre les fichiers CSS. Merci beaucoup
Good Job
Merci a toi aussi d'avoir lu et essayer l'example.
Je suis en train de l'adapter a un projet je veux augmenter le nombre de step. Je passerai mon en cas de problème.
Ok y a pas de souci et bonne chance
Salut bro j'ai repris ton formulaire tout se passe bien sauf que quand j'ajoute bcp de contenu le formulaire deborde y'a t'il un moyen de garder le formulaire dans le body!
Salut! Tu changes juste la hauteur du stepper. La hauteur maximale du
body
est de100vh
(vh
= viewport height => hauteur de l'écran), tu joues avec la hauteur du formulaire pour qu'elle ne dépasse pas100vh
.Hello, ibrahima
je voudrais refaire ton formulaire mais tous mes formulaires s'affichent sur la même page. Je peux avoir une indication sur un détail que j'ai peut raté? merci d'avance
Salut! Très bonne idée. Tu peux me partager ton code? Je pense que tu dois changer la position des formulaires et de leur conteneur. Pour chaque formulaire
position:absolute
et pour le conteneurposition:relative
. Essaie de mettre ton code sur github ou codePen et partage le lien.