A CSS-only responsive Stepper component

Written by Web Developer

February 9, 2023
A CSS-only responsive Stepper component

In this article, we will build a component commonly used everywhere especially when it comes to multi-step forms: The stepper component. If you are not familiar with such a component here is a figure to give you an idea.

Overview of a stepper component

The goal is to use the smallest HTML code possible and at the same time make the component scalable. You will be able to add as many steps as you want without the need to touch the CSS code. We will also make it responsive and the “active” steps can be controlled easily.

The HTML markup


Let’s start with the HTML code which is a list defined using the <ol> element:

<ol class="stepper">
   <li>Step A</li>
   <li class="active">Step B</li>
   <li>Step C</li>
   <li>Step D</li>
</ol>

We don’t need to clutter our code with a lot of divs. A simple list can do the job. Also, note the use of the active class on the second element that defines the current or active step. This class will control the coloration as you can see in the first figure where both Step A and Step B are in purple (we will call it the “active” coloration) and the other one in grey (we will call it the “default” coloration).

Defining the variables


Let’s define a few variables to easily control our stepper.

ol.stepper {
  --default-b: lightgrey;
  --default-c: black;
  --active-b: purple;
  --active-c: white;
  --circle: 3.5em; /* size of circle */
  --b: 5px; /* line thickness */
}

The code should be self-explanatory. We have the color variables and the ones that control the size of the circle and the line.

Styling the Stepper


Here, we are going to rely on flexbox and the use of space-between to correctly place the steps inside the stepper:

ol.stepper {
  display: flex;
  list-style: none;
  justify-content: space-between;
  margin: 20px;
  padding: 0;
  font-size: 22px;
}

This configuration allows us to have as many steps as we want without having to adjust the position of each one. The space-between will do the job for us

You are probably wondering why we removed the numbers using list-style: none. It’s because we cannot style the default numeration so we will disable it and replace it with a custom one using counter.

ol.stepper {
  counter-reset: step;
}
ol.stepper li::before {
  content: counter(step) " ";
  counter-increment: step;
}

Styling the steps


For the steps we will use a CSS grid to have a 2-rows configuration plus some basic CSS to style the numbers:

Overview of one default step
ol.stepper li {
  display: grid;
  place-items: center;
  gap: 5px;
}
ol.stepper li::before {
  content: counter(step) " ";
  counter-increment: step;
  display: grid;
  place-content: center;
  height: var(--circle);
  aspect-ratio: 1;
  background: var(--active-b);
  color: var(--active-c);
  border: 5px solid #fff;
  box-sizing: border-box;
  border-radius: 50%;
}
ol.stepper li.active ~ li::before{
  background: var(--default-b);
  color: var(--default-c);
}

The tricky part here is how we handle the coloration. All the items will have the “active" coloration but using the sibling selector ~ we make all the elements that are placed after the active element with the “default” coloration. This way, we only need to place the active class on the active/current step and the CSS will do the job for us.

We are almost done! All that is missing is the line between the elements and to do this we will first define a background on the stepper element to create the line with the default coloration

background: 
    linear-gradient(var(--default-b) 0 0) no-repeat
    50% calc((var(--circle) - var(--b))/2)/100% var(--b);

Note the use of the different variables we defined previously. This will create a line with a thickness equal to --b and a width equal to 100%. For the position, it needs to be placed at the center of the circle so we offset it from the top by half the circle size minus half the line size.

The above will create a line with only the “default" coloration. We still need a line with the “active” coloration and for this one, we will use the pseudo-element of the active element

ol.stepper li.active::after {
  content: "";
  position: absolute;
  height: var(--b);
  right: 100%;
  top: calc((var(--circle) - var(--b))/2); /* same offset as the background */
  width: 100vw; /* very big value */
  background: var(--active-b);
}

This will create a very big line placed at the right of the active line with the “active” coloration that will overlap the previous one. We also need to hide the overflow on the main element since we are using a big value that will create an overflow. Don’t forget to adjust the z-indexes if needed as well.

Here is the demo with the full code:

Our stepper component is now perfect!

Note the small gap between the lines and the circle. It’s the use of the white border so if you have a different background color you need to adjust the color to match the one of your background.

Making the Stepper responsive


To make our stepper responsive we will switch from a horizontal configuration to a vertical one.

The vertical version of the Stepper

For this, we are going to use a media query and adjust a few values

@media (max-width: 600px) { 
  ol.stepper {
   display: grid;
   gap: 20px;
   background: 
     linear-gradient(var(--default-b) 0 0) no-repeat
     calc((var(--circle) - var(--b))/2) 50%/var(--b) 100%;
  }
  ol.stepper li {
    display: flex;
  }
  ol.stepper li.active::after {
    content: "";
    position: absolute;
    width: var(--b);
    bottom: 100%;
    left: calc((var(--circle) - var(--b))/2);
    top: auto;
    right: auto;
    height: 100vw;
    background: var(--active-b);
  }
}

We switch from flexbox to CSS grid on the main element to move from one row of elements to one element per row. We apply the same logic on the step element by using flexbox instead of CSS grid to do the opposite.

For the lines, you will notice that in the background property, we kept the same values but the order is different. What we have used for the width is now a height and vice versa. Same logic for the pseudo element. What we used for right is used with bottom, width becomes height, top becomes left, and so on.

Here is the full demo:

25%

💸 EXTRA 25% OFF ALL VERPEX MANAGED CLOUD SERVERS

with the discount code

SERVERS-SALE

Use Code Now

Conclusion


I hope you enjoyed this step-by-step tutorial to create a stepper component. Using a basic HTML code, all you have to do is to update a few variables and place the active class on the current element and you are done!

Frequently Asked Questions

How to design a podcast website?

When using a CMS, designing your website will be quick and easy. You can add a template you’ve created or pick one of the pre-made templates that the CMS features in its library.

What type of design should my fitness blog have?

When you’re a beginner, don’t go crazy with the design of the site. The most important thing is to have a site that looks professional, easy to read, and fast.

How do I choose a design for my website?

One of the most important things when creating a website for your art is the design. Even though your pieces of art might be amazing, people will leave if your site is hard to navigate. This is why it’s important that the site is easy on the eyes and easy to navigate.

Can I afford a website builder?

Yes. Besides paid website builders, there are also free ones; however, they come with fewer options.

Discount

💰 50% OFF YOUR FIRST MONTH ON MANAGED CLOUD SERVERS

with the discount code

SERVERS-SALE

Use Code Now
Jivo Live Chat