//PEN HEADER
header.header
  h1.header__title Multi Step Form with animations
  .header__btns.btns
    a.header__btn.btn(href="https://github.com/nat-davydova/multisteps-form" title="Check on Github" target="_blank") Check on Github
    
//PEN CONTENT     
.content
  
  //content inner
  .content__inner
    
    .container
    
      //content title
      h2.content__title.content__title--m-sm Pick animation type
      
      //animations form
      form.pick-animation.my-4
        .form-row
          .col-5.m-auto

            select.pick-animation__select.form-control
              option(value="scaleIn" selected) ScaleIn
              option(value="scaleOut") ScaleOut
              option(value="slideHorz") SlideHorz
              option(value="slideVert") SlideVert
              option(value="fadeIn") FadeIn
    
      //content title
      h2.content__title Click on steps or 'Prev' and 'Next' buttons
    
    .container.overflow-hidden
    
      //multisteps-form
      .multisteps-form

        //progress bar
        .row

          .col-12.col-lg-8.ml-auto.mr-auto.mb-4

            .multisteps-form__progress

              button.multisteps-form__progress-btn.js-active(type="button" title="User Info") User Info

              button.multisteps-form__progress-btn(type="button" title="Address") Address

              button.multisteps-form__progress-btn(type="button" title="Order Info") Order Info

              button.multisteps-form__progress-btn(type="button" title="Comments") Comments        

        //form panels
        .row

          .col-12.col-lg-8.m-auto

            form.multisteps-form__form

              //single form panel
              .multisteps-form__panel.shadow.p-4.rounded.bg-white.js-active(data-animation="scaleIn")

                h3.multisteps-form__title Your User Info

                .multisteps-form__content

                  .form-row.mt-4

                    .col-12.col-sm-6

                      input.multisteps-form__input.form-control(type="text" placeholder="First Name")

                    .col-12.col-sm-6.mt-4.mt-sm-0

                      input.multisteps-form__input.form-control(type="text" placeholder="Last Name")

                  .form-row.mt-4

                    .col-12.col-sm-6

                      input.multisteps-form__input.form-control(type="text" placeholder="Login")

                    .col-12.col-sm-6.mt-4.mt-sm-0

                      input.multisteps-form__input.form-control(type="email" placeholder="Email")

                  .form-row.mt-4

                   .col-12.col-sm-6

                    input.multisteps-form__input.form-control(type="password" placeholder="Password")

                   .col-12.col-sm-6.mt-4.mt-sm-0

                    input.multisteps-form__input.form-control(type="password" placeholder="Repeat Password")

                  .button-row.d-flex.mt-4

                    button.btn.btn-primary.ml-auto.js-btn-next(type="button" title="Next") Next

              //single form panel
              .multisteps-form__panel.shadow.p-4.rounded.bg-white(data-animation="scaleIn")

                h3.multisteps-form__title Your Address

                .multisteps-form__content

                  .form-row.mt-4

                    .col

                      input.multisteps-form__input.form-control(type="text" placeholder="Address 1")

                  .form-row.mt-4

                    .col
                      input.multisteps-form__input.form-control(type="text" placeholder="Address 2")

                  .form-row.mt-4

                    .col-12.col-sm-6

                      input.multisteps-form__input.form-control(type="text" placeholder="City")

                    .col-6.col-sm-3.mt-4.mt-sm-0

                      select.multisteps-form__select.form-control
                        option(selected) State...
                        option ...

                    .col-6.col-sm-3.mt-4.mt-sm-0

                      input.multisteps-form__input.form-control(type="text" placeholder="Zip")

                  .button-row.d-flex.mt-4

                    button.btn.btn-primary.js-btn-prev(type="button" title="Prev") Prev
                    button.btn.btn-primary.ml-auto.js-btn-next(type="button" title="Next") Next

              //single form panel
              .multisteps-form__panel.shadow.p-4.rounded.bg-white(data-animation="scaleIn")

                h3.multisteps-form__title Your Order Info

                .multisteps-form__content

                  .row
                    .col-12.col-md-6.mt-4

                      .card.shadow-sm
                        .card-body

                          h5.card-title Item Title
                          p.card-text Small and nice item description
                          a.btn.btn-primary(href="#" title="Item Link") Item Link

                    .col-12.col-md-6.mt-4

                      .card.shadow-sm
                        .card-body

                          h5.card-title Item Title
                          p.card-text Small and nice item description
                          a.btn.btn-primary(href="#" title="Item Link") Item Link

                  .row
                    .button-row.d-flex.mt-4.col-12

                      button.btn.btn-primary.js-btn-prev(type="button" title="Prev") Prev
                      button.btn.btn-primary.ml-auto.js-btn-next(type="button" title="Next") Next

              //single form panel
              .multisteps-form__panel.shadow.p-4.rounded.bg-white(data-animation="scaleIn")

                h3.multisteps-form__title Additional Comments

                .multisteps-form__content

                  .form-row.mt-4

                    textarea.multisteps-form__textarea.form-control(placeholder="Additional Comments and Requirements")

                  .button-row.d-flex.mt-4

                    button.btn.btn-primary.js-btn-prev(type="button" title="Prev") Prev
                    button.btn.btn-success.ml-auto(type="button" title="Send") Send
View Compiled
//mixins
@mixin transition-mix ($property: all, $duration: 0.2s, $timing: linear, $delay: 0s) {
  transition-property: $property;
  transition-duration: $duration;
  transition-timing-function: $timing;
  transition-delay: $delay;
}

@mixin position-absolute ($top: null, $left: null, $right: null, $bottom: null) {
  position: absolute;
  top: $top;
  left: $left;
  right: $right;
  bottom: $bottom;
}

//basic variables
$theme-font-color: #2c2c2c;

//common styles
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font: {
    family: 'Poppins', sans-serif;
    size: 16px;
  }
  color: $theme-font-color;
  
  a {
    color: inherit;
    text-decoration: none;
  }
}

.header__btn {
  @include transition-mix;
  
  padding: 10px 20px;
  display: inline-block;
  margin-right: 10px;
  
  background-color: #fff;
  border: 1px solid $theme-font-color;
  border-radius: 3px;
  
  cursor: pointer;
  
  outline: none;
  
  &:last-child {
    margin-right: 0;
  }
  
  &:hover,
  &.js-active{
    color: #fff;
    
    background-color: $theme-font-color;
  }
}

//header styles
.header {
  max-width: 600px;
  margin: 50px auto;
  
  text-align: center;
}

.header__title {
  margin-bottom: 30px;
  
   font: {
    size: 2.1rem;
  }
}

//content styles
.content {
  width: 95%;
  margin: 0 auto 50px;
}

.content__title {
  margin-bottom: 40px;
  
  font: {
    size: 20px;
  }
  text-align: center;
}

.content__title--m-sm {
  margin-bottom: 10px;
}

//multisteps variables
$color-secondary: #6c757d;
$color-primary: #007bff;

$btn-offset-vert: 20px;
$btn-circle-decor-dimensions: 13px;

//multisteps progress styles
.multisteps-form__progress {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}

.multisteps-form__progress-btn {
  @include transition-mix($duration: .15s);
  
  position: relative;
  
  padding-top: $btn-offset-vert;
  
  color: rgba($color-secondary, .7);
  
  text-indent: -9999px;
  
  border: none;
  background-color: transparent;
  outline: none !important;
  
  cursor: pointer;
  
  @media (min-width: 500px) {
    text-indent: 0;
  }
  
  
  //circle decoration
  &:before {
    @include position-absolute($top: 0, $left: 50%);
    
    display: block;
    width: $btn-circle-decor-dimensions;
    height: $btn-circle-decor-dimensions;
    
    content: '';
    
    transform: translateX(-50%);
    
    transition: all .15s linear 0s, 
      transform .15s cubic-bezier(0.05, 1.09, 0.16, 1.4) 0s;
    
    border: 2px solid currentColor;
    border-radius: 50%;
    background-color: #fff;
    
    box-sizing: border-box;
    
    z-index: 3;
  }
  
  //line decoration
  &:after {
    @include position-absolute($top: $btn-offset-vert/4, $left: calc(-50% - #{$btn-circle-decor-dimensions} / 2));
  @include transition-mix($duration: .15s);
  
    display: block;
    width: 100%;
    height: 2px;
    
    content: '';
    
    background-color: currentColor;
  
    z-index: 1;
  }

  //last child - without line decoration
  &:first-child {
    
    &:after {
      display: none;
    }
  }

  //active styles
  &.js-active {
    color: $color-primary;
    
    &:before {      
      transform: translateX(-50%) scale(1.2);
      
      background-color: currentColor;
    }
  }
}

//multisteps form styles
.multisteps-form__form {
  position: relative;
}

//multisteps panels styles
.multisteps-form__panel {
  @include position-absolute($top: 0, $left: 0);
  
  width: 100%;
  height: 0;
  
  opacity: 0;
  visibility: hidden;
  
  //active panels
  &.js-active { 
    height: auto;
    
    opacity: 1;
    visibility: visible;
  }
  
  //scaleOut animation
  &[data-animation="scaleOut"] {
    transform: scale(1.1);
    
    &.js-active {
      @include transition-mix;
    
      transform: scale(1);
    }
  }
  
  //slideHorz animation
  &[data-animation="slideHorz"] {
    left: 50px;
    
    &.js-active {
      @include transition-mix($duration: .25s, $timing: cubic-bezier(0.2, 1.13, 0.38, 1.43));
    
      left: 0;
    }
  }
  
  //slideVert animation
  &[data-animation="slideVert"] {
    top: 30px;
    
    &.js-active {
      @include transition-mix();
    
      top: 0;
    }
  }
  
  //fadeIn animation
  &[data-animation="fadeIn"] {

    
    &.js-active {
      @include transition-mix($duration: .3s);
    }
  }
  
  //scaleOut
  &[data-animation="scaleIn"] {
    transform: scale(.9);
    
    &.js-active {
      @include transition-mix;
    
      transform: scale(1);
    }
  }
}
View Compiled
//DOM elements
const DOMstrings = {
  stepsBtnClass: 'multisteps-form__progress-btn',
  stepsBtns: document.querySelectorAll(`.multisteps-form__progress-btn`),
  stepsBar: document.querySelector('.multisteps-form__progress'),
  stepsForm: document.querySelector('.multisteps-form__form'),
  stepsFormTextareas: document.querySelectorAll('.multisteps-form__textarea'),
  stepFormPanelClass: 'multisteps-form__panel',
  stepFormPanels: document.querySelectorAll('.multisteps-form__panel'),
  stepPrevBtnClass: 'js-btn-prev',
  stepNextBtnClass: 'js-btn-next'
};

//remove class from a set of items
const removeClasses = (elemSet, className) => {
  
  elemSet.forEach(elem => {
    
    elem.classList.remove(className);
    
  });
  
};

//return exect parent node of the element
const findParent = (elem, parentClass) => {
  
  let currentNode = elem;

  while(! (currentNode.classList.contains(parentClass))) {
    currentNode = currentNode.parentNode;
  }
  
  return currentNode;
  
};

//get active button step number
const getActiveStep = elem => {
  return Array.from(DOMstrings.stepsBtns).indexOf(elem);
};

//set all steps before clicked (and clicked too) to active
const setActiveStep = (activeStepNum) => {
  
  //remove active state from all the state
  removeClasses(DOMstrings.stepsBtns, 'js-active');
  
  //set picked items to active
  DOMstrings.stepsBtns.forEach((elem, index) => {
    
    if(index <= (activeStepNum) ) {
      elem.classList.add('js-active');
    }
    
  });
};

//get active panel
const getActivePanel = () => {
  
  let activePanel;
  
  DOMstrings.stepFormPanels.forEach(elem => {
    
    if(elem.classList.contains('js-active')) {
      
      activePanel = elem;
      
    }
    
  });
  
  return activePanel;
                                    
};

//open active panel (and close unactive panels)
const setActivePanel = activePanelNum => {
  
  //remove active class from all the panels
  removeClasses(DOMstrings.stepFormPanels, 'js-active');
  
  //show active panel
  DOMstrings.stepFormPanels.forEach((elem, index) => {
    if(index === (activePanelNum)) {
      
      elem.classList.add('js-active');
   
      setFormHeight(elem);
      
    }
  })
  
};

//set form height equal to current panel height
const formHeight = (activePanel) => {
  
  const activePanelHeight = activePanel.offsetHeight;
  
  DOMstrings.stepsForm.style.height = `${activePanelHeight}px`;
  
};

const setFormHeight = () => {
  const activePanel = getActivePanel();

  formHeight(activePanel);
}

//STEPS BAR CLICK FUNCTION
DOMstrings.stepsBar.addEventListener('click', e => {
  
  //check if click target is a step button
  const eventTarget = e.target;
  
  if(!eventTarget.classList.contains(`${DOMstrings.stepsBtnClass}`)) {
    return;
  }
  
  //get active button step number
  const activeStep = getActiveStep(eventTarget);
  
  //set all steps before clicked (and clicked too) to active
  setActiveStep(activeStep);
  
  //open active panel
  setActivePanel(activeStep);
});

//PREV/NEXT BTNS CLICK
DOMstrings.stepsForm.addEventListener('click', e => {
  
  const eventTarget = e.target;
  
  //check if we clicked on `PREV` or NEXT` buttons
  if(! ( (eventTarget.classList.contains(`${DOMstrings.stepPrevBtnClass}`)) || (eventTarget.classList.contains(`${DOMstrings.stepNextBtnClass}`)) ) ) 
  {
    return;
  }
  
  //find active panel
  const activePanel = findParent(eventTarget, `${DOMstrings.stepFormPanelClass}`);
  
  let activePanelNum = Array.from(DOMstrings.stepFormPanels).indexOf(activePanel);
  
  //set active step and active panel onclick
  if(eventTarget.classList.contains(`${DOMstrings.stepPrevBtnClass}`)) {
    activePanelNum--;
  
  } else {
    
    activePanelNum++;
  
  }
  
  setActiveStep(activePanelNum);
  setActivePanel(activePanelNum);
  
});

//SETTING PROPER FORM HEIGHT ONLOAD
window.addEventListener('load', setFormHeight, false);

//SETTING PROPER FORM HEIGHT ONRESIZE
window.addEventListener('resize', setFormHeight, false);

//changing animation via animation select !!!YOU DON'T NEED THIS CODE (if you want to change animation type, just change form panels data-attr)

const setAnimationType = (newType) => {
  DOMstrings.stepFormPanels.forEach(elem => {
    elem.dataset.animation = newType;
  })
};

//selector onchange - changing animation
const animationSelect = document.querySelector('.pick-animation__select');

animationSelect.addEventListener('change', () => {
  const newAnimationType = animationSelect.value;
  
  setAnimationType(newAnimationType);
});
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css
  2. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js