How to Create a Step Progress Bar With Tailwind

The very first thing we need is the HTML structure.

index.html

<div class="stepper-wrapper">
  <div class="stepper-item completed">
    <div class="step-counter">1</div>
    <div class="step-name">First</div>
  </div>
  <div class="stepper-item completed">
    <div class="step-counter">2</div>
    <div class="step-name">Second</div>
  </div>
  <div class="stepper-item active">
    <div class="step-counter">3</div>
    <div class="step-name">Third</div>
  </div>
  <div class="stepper-item">
    <div class="step-counter">4</div>
    <div class="step-name">Forth</div>
  </div>
</div>

We have a wrapper that contains all of the steps. And each step consist of a pair of <div>s: one for the number and the other for the description.

As you can see, each step can have states: completed or active. Now let’s take a look at the CSS:

styles.css

.stepper-wrapper {
  font-family: Arial;
  margin-top: 50px;
  display: flex;
  justify-content: space-between;
  margin-bottom: 20px;
}
.stepper-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;

  @media (max-width: 768px) {
    font-size: 12px;
  }
}

.stepper-item::before {
  position: absolute;
  content: "";
  border-bottom: 2px solid #ccc;
  width: 100%;
  top: 20px;
  left: -50%;
  z-index: 2;
}

.stepper-item::after {
  position: absolute;
  content: "";
  border-bottom: 2px solid #ccc;
  width: 100%;
  top: 20px;
  left: 50%;
  z-index: 2;
}

.stepper-item .step-counter {
  position: relative;
  z-index: 5;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #ccc;
  margin-bottom: 6px;
}

.stepper-item.active {
  font-weight: bold;
}

.stepper-item.completed .step-counter {
  background-color: #4bb543;
}

.stepper-item.completed::after {
  position: absolute;
  content: "";
  border-bottom: 2px solid #4bb543;
  width: 100%;
  top: 20px;
  left: 50%;
  z-index: 3;
}

.stepper-item:first-child::before {
  content: none;
}

.stepper-item:last-child::after {
  content: none;
}

While a little verbose, the code above is easy to read.

output.html

<div class="mt-auto flex w-full justify-between">
  <!-- first step -->
  <div class="before:content-[''] after:content-[''] relative flex flex-1 flex-col items-center before:absolute before:-left-1/2 before:top-4 before:z-[2] before:w-full before:border-b-2 before:border-blue-500 after:absolute after:left-1/2 after:top-4 after:z-[2] after:w-full after:border-b-2 first:before:content-none last:after:content-none">
    <div class="relative z-[5] mb-[6px] flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 text-white">
      1
    </div>
    <div class="text-sm text-black">
      Step 1
    </div>
  </div>
  
  <!-- second step -->
  <div class="before:content-[''] after:content-[''] relative flex flex-1 flex-col items-center before:absolute before:-left-1/2 before:top-4 before:z-[2] before:w-full before:border-b-2 before:border-dashed before:border-gray-300 after:absolute after:left-1/2 after:top-4 after:z-[2] after:w-full after:border-b-2 first:before:content-none last:after:content-none">
    <div class="relative z-[5] mb-[6px] flex h-8 w-8 items-center justify-center rounded-full bg-gray-100 border border-gray-300">
      2
    </div>
  </div>
  
  <!-- third step -->
  <div class="before:content-[''] after:content-[''] relative flex flex-1 flex-col items-center before:absolute before:-left-1/2 before:top-4 before:z-[2] before:w-full before:border-b-2 before:border-dashed before:border-gray-300 after:absolute after:left-1/2 after:top-4 after:z-[2] after:w-full after:border-b-2 first:before:content-none last:after:content-none">
    <div class="relative z-[5] mb-[6px] flex h-8 w-8 items-center justify-center rounded-full bg-gray-100 border border-gray-300">
      3
    </div>
  </div>
</div>

Leave a comment

Your email address will not be published. Required fields are marked *