Build A Animated Tab Bar Using HTML, CSS and Javascript

By Bytewebster - September 25, 2022



Welcome to the bytewebster Project blogs. In this JavaScript project, we will create an active animated tab bar from scratch. If you are learning JavaScript or web development, then you should make this project, it will make your JavaScript stronger. So let us first know its working.

Working:

We have given 5 options in this tab bar, if you want, you can also call them Icons. First is the image option then second is the home and then the menu, notification, and cart option is given. When you click on the Home option, a small popup will appear on the top of the tab bar and then in that too you will get another three options. And clicking on any option shows a color hover effect. Its hover effect also feels much smoother on the movement of the cursor.

                     
                 

Detailed Overview of Project


If you want to make this project by yourself without downloading the source code files. So then here you have to create three files The first file will be HTML and the second will be CSS and the last will be JavaScript and then you have to take those files to your text editor where you will create this project.

If you are learning web development then you will already know this still, we are telling this for some beginners.


HTML Structure

We start with HTML, in which we have to use a nav tag. Then for its tabs, we have made the div tag to whom we have given classes.

Second, we have created a wrapper class with the help of a div tag. after that, we created 3 filter tabs here whose names we have kept inside the list tag

Below the filter tabs, we have created a container for the rest of the tabs and we have also placed them inside the list tags. In this, we have used the image in the first list, if you want, you can also use the SVG icon in its place.

For the rest of the other tabs, we have taken the icons of SVG, if you want, you can also use its icons by applying Bootstrap Icon CDN. And here we have made all the tabs in the form of buttons.


<nav class="amazing-tabs">
  <div class="filters-container">
    <div class="filters-wrapper">
      <ul class="filter-tabs">
        <li>
          <button class="filter-button filter-active" data-translate-value="0">
            Trending
          </button>
        </li>
        <li>
          <button class="filter-button" data-translate-value="100%">
            Popular
          </button>
        </li>
        <li>
          <button class="filter-button" data-translate-value="200%">
            Following
          </button>
        </li>
      </ul>
      <div class="filter-slider" aria-hidden="true">
        <div class="filter-slider-rect">&nbsp;</div>
      </div>
    </div>
  </div>
  <div class="main-tabs-container">
    <div class="main-tabs-wrapper">
      <ul class="main-tabs">
        <li>
          <button class="round-button" data-translate-value="0" data-color="red">
            <span class="avatar">
              <img src="https://bytewebster.com/img/logo.png" alt="user avatar" />
            </span>
          </button>
        </li>
        <li>
          <button class="round-button gallery active" style="--round-button-active-color: #2962ff" data-translate-value="100%" data-color="blue">
            <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"viewBox="0 0 26.39 26.39" style="enable-background:new 0 0 26.39 26.39;" xml:space="preserve">
          <g>
	 <g id="c14_house">
		<path d="M3.588,24.297c0,0-0.024,0.59,0.553,0.59c0.718,0,6.652-0.008,6.652-0.008l0.01-5.451c0,0-0.094-0.898,0.777-0.898h2.761
			c1.031,0,0.968,0.898,0.968,0.898l-0.012,5.434c0,0,5.628,0,6.512,0c0.732,0,0.699-0.734,0.699-0.734V14.076L13.33,5.913
			l-9.742,8.164C3.588,14.077,3.588,24.297,3.588,24.297z"/>
		<path d="M0,13.317c0,0,0.826,1.524,2.631,0l10.781-9.121l10.107,9.064c2.088,1.506,2.871,0,2.871,0L13.412,1.504L0,13.317z"/>
		<polygon points="23.273,4.175 20.674,4.175 20.685,7.328 23.273,9.525 		"/>
	 </g>
	 <g id="Capa_1_216_">
	 </g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g>
        </svg>
          </button>
        </li>
        <li>
          <button class="round-button" style="--round-button-active-color: #00c853" data-translate-value="200%" data-color="green">
            <svg fill="currentColor" viewBox="0 0 16 16">
              <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
              <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
            </svg>
          </button>
        </li>
        <li>
          <button class="round-button" style="--round-button-active-color: #aa00ff" data-translate-value="300%" data-color="purple">
            <svg fill="currentColor" viewBox="0 0 16 16">
              <path d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2zM8 1.918l-.797.161A4.002 4.002 0 0 0 4 6c0 .628-.134 2.197-.459 3.742-.16.767-.376 1.566-.663 2.258h10.244c-.287-.692-.502-1.49-.663-2.258C12.134 8.197 12 6.628 12 6a4.002 4.002 0 0 0-3.203-3.92L8 1.917zM14.22 12c.223.447.481.801.78 1H1c.299-.199.557-.553.78-1C2.68 10.2 3 6.88 3 6c0-2.42 1.72-4.44 4.005-4.901a1 1 0 1 1 1.99 0A5.002 5.002 0 0 1 13 6c0 .88.32 4.2 1.22 6z" />
            </svg>
          </button>
        </li>
        <li>
          <button class="round-button" style="--round-button-active-color: #ff6d00" data-translate-value="400%" data-color="orange">
            <svg fill="currentColor" viewBox="0 0 16 16">
              <path d="M0 1.5A.5.5 0 0 1 .5 1H2a.5.5 0 0 1 .485.379L2.89 3H14.5a.5.5 0 0 1 .491.592l-1.5 8A.5.5 0 0 1 13 12H4a.5.5 0 0 1-.491-.408L2.01 3.607 1.61 2H.5a.5.5 0 0 1-.5-.5zM3.102 4l1.313 7h8.17l1.313-7H3.102zM5 12a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm7 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm-7 1a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm7 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" />
            </svg>
          </button>
        </li>
      </ul>
      <div class="main-slider" aria-hidden="true">
        <div class="main-slider-circle">&nbsp;</div>
      </div>
      <p style="font-family: arial; text-align: center;">
      	BYTEWEBSTER
      </p>
    </div>
  </div>
</nav>


Styling With CSS

It will look very basic without any CSS, now we need to style it so that its interface looks great

The code to style it is given below, you can go and see it. right now since this is a JavaScript project, we will focus on the JavaScript part of it.


@import url("https://fonts.googleapis.com/css2?family=Open+Sans&display=swap");

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  --background-color: #bbdefb;
  --blue-50: #e3f2fd;
  --blue-100: #bbdefb;
  --blue-A700: #2962ff;
  --green-50: #e8f5e9;
  --green-100: #c8e6c9;
  --green-A700: #00c853;
  --purple-50: #f3e5f5;
  --purple-100: #e1bee7;
  --purple-A700: #aa00ff;
  --orange-50: #fff3e0;
  --orange-100: #ffe0b2;
  --orange-A700: #ff6d00;
  --orange-700: #f57c00;
  --grey-900: #212121;
  --white: #ffffff;
  --round-button-active-color: #212121;
  --translate-main-slider: 100%;
  --main-slider-color: #e3f2fd;
  --translate-filters-slider: 0;
  --filters-container-height: 3.8rem;
  --filters-wrapper-opacity: 1;
}

html {
  font-size: 62.5%;
}

html,
body {
  height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transition: background-color 0.4s ease-in-out;
  background-color: var(--background-color);
}

button {
  border: none;
  cursor: pointer;
  background-color: transparent;
  outline: none;
}

nav.amazing-tabs {
  background-color: var(--white);
  border-radius: 2.5rem;
  user-select: none;
  padding-top: 1rem;
}

.main-tabs-container {
  padding: 0 1rem 1rem 1rem;
}

.main-tabs-wrapper {
  position: relative;
}

ul.main-tabs,
ul.filter-tabs {
  list-style-type: none;
  display: flex;
}

ul.main-tabs li {
  display: inline-flex;
  position: relative;
  padding: 1.5rem;
  z-index: 1;
}

.avatar,
.avatar img {
  height: 4rem;
  width: 4rem;
  border-radius: 50%;
  pointer-events: none;
}

.avatar img {
  object-fit: cover;
}

.round-button {
  height: 4.8rem;
  width: 4.8rem;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--grey-900);
  transition: color 0.2s ease-in-out;
}

.round-button:hover,
.round-button.active {
  color: var(--round-button-active-color);
}

.round-button svg {
  pointer-events: none;
  height: 2.8rem;
  width: 2.8rem;
  transform: translate(0, 0);
}

.main-slider {
  pointer-events: none;
  position: absolute;
  top: 0;
  left: 0;
  padding: 1.5rem;
  z-index: 0;
  transition: transform 0.4s ease-in-out;
  transform: translateX(var(--translate-main-slider));
}

.main-slider-circle {
  height: 4.8rem;
  width: 4.8rem;
  border-radius: 50%;
  transition: background-color 0.4s ease-in-out;
  background-color: var(--main-slider-color);
}

.animate-jello {
  animation: jello-horizontal 0.9s both;
}

@keyframes jello-horizontal {
  0% {
    transform: scale3d(1, 1, 1);
  }
  30% {
    transform: scale3d(1.25, 0.75, 1);
  }
  40% {
    transform: scale3d(0.75, 1.25, 1);
  }
  50% {
    transform: scale3d(1.15, 0.85, 1);
  }
  65% {
    transform: scale3d(0.95, 1.05, 1);
  }
  75% {
    transform: scale3d(1.05, 0.95, 1);
  }
  100% {
    transform: scale3d(1, 1, 1);
  }
}

.filters-container {
  overflow: hidden;
  padding: 0 3rem;
  transition: max-height 0.4s ease-in-out;
  max-height: var(--filters-container-height);
}

.filters-wrapper {
  position: relative;
  transition: opacity 0.2s ease-in-out;
  opacity: var(--filters-wrapper-opacity);
}

.filter-tabs {
  border-radius: 1rem;
  padding: 0.3rem;
  overflow: hidden;
  background-color: var(--orange-50);
}

.filter-tabs li {
  position: relative;
  z-index: 1;
  display: flex;
  flex: 1 0 33.33%;
}

.filter-button {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0.8rem;
  flex-grow: 1;
  height: 3rem;
  padding: 0 1.5rem;
  color: var(--orange-700);
  font-family: "Open Sans", sans-serif;
  font-weight: 400;
  font-size: 1.4rem;
}

.filter-button.filter-active {
  transition: color 0.4s ease-in-out;
  color: var(--grey-900);
}

.filter-slider {
  pointer-events: none;
  position: absolute;
  padding: 0.3rem;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
}

.filter-slider-rect {
  height: 3rem;
  width: 33.33%;
  border-radius: 0.8rem;
  background-color: var(--white);
  box-shadow: 0 0.1rem 1rem -0.4rem rgba(0, 0, 0, 0.12);
  transition: transform 0.4s ease-in-out;
  transform: translateX(var(--translate-filters-slider));
}


JavaScript Explanation

its Javascript code starts by creating a variable called mainTabs. This is the element that will contain all of the tabs in our app.

Next, we create a variable called mainSliderCircle and set it to be equal to document.querySelector(".main-slider-circle").The slider circle is the element that contains all of our sliders for this tab.

after that we create variables called roundButtons and colors which are arrays with objects inside them containing values like "blue" or "green." We then use getColor() function to return an object's value from each array based on its name (e.g., blue).The code is used to get the color of a given variant.

The code starts by creating a function called handleActiveTab that takes three parameters: tabs, event, and className. The first parameter is an array of all the active tab elements in the document.

The second parameter is the event object from which we can get information about what happened during this click event. The third parameter is a string that will be used to set or remove CSS classes on each of the active tab elements based on their color value.

by iterating through all of the active tab elements in mainTabs and removing any CSS classes with "className" from them if they are not currently being targeted by an element with "className".If there was no target for this click event then it adds "className" to whatever element was clicked on (event).

It also adds back the "animate-jello" class so that when you click on an active tab, you can see what's going on with your animation. The code is adding a translate value of 50 pixels for each time you click on an active tab, which translates into 100 pixels total (50 x 2).The code is used to change the background color of the main slider when a round button is clicked.

The target classList contains "round-button" and the offsetWidth is removed from the animate-jello class. The animate-jello class is then added back with the translate value set to targetTranslateValue which will be translated into 50% of its original size. The background color changes as well and now matches that of the active tab's colors.


const mainTabs = document.querySelector(".main-tabs");
const mainSliderCircle = document.querySelector(".main-slider-circle");
const roundButtons = document.querySelectorAll(".round-button");

const colors = {
  blue: {
    50: {
      value: "#e3f2fd"
    },
    100: {
      value: "#bbdefb"
    }
  },
  green: {
    50: {
      value: "#e8f5e9"
    },
    100: {
      value: "#c8e6c9"
    }
  },
  purple: {
    50: {
      value: "#f3e5f5"
    },
    100: {
      value: "#e1bee7"
    }
  },
  orange: {
    50: {
      value: "#ffe0b2"
    },
    100: {
      value: "#ffe0b2"
    }
  },
  red: {
    50: {
      value: "#ffebee"
    },
    100: {
      value: "#ffcdd2"
    }
  }
};

const getColor = (color, variant) => {
  return colors[color][variant].value;
};

const handleActiveTab = (tabs, event, className) => {
  tabs.forEach((tab) => {
    tab.classList.remove(className);
  });

  if (!event.target.classList.contains(className)) {
    event.target.classList.add(className);
  }
};

mainTabs.addEventListener("click", (event) => {
  const root = document.documentElement;
  const targetColor = event.target.dataset.color;
  const targetTranslateValue = event.target.dataset.translateValue;

  if (event.target.classList.contains("round-button")) {
    mainSliderCircle.classList.remove("animate-jello");
    void mainSliderCircle.offsetWidth;
    mainSliderCircle.classList.add("animate-jello");

    root.style.setProperty("--translate-main-slider", targetTranslateValue);
    root.style.setProperty("--main-slider-color", getColor(targetColor, 50));
    root.style.setProperty("--background-color", getColor(targetColor, 100));

    handleActiveTab(roundButtons, event, "active");

    if (!event.target.classList.contains("gallery")) {
      root.style.setProperty("--filters-container-height", "0");
      root.style.setProperty("--filters-wrapper-opacity", "0");
    } else {
      root.style.setProperty("--filters-container-height", "3.8rem");
      root.style.setProperty("--filters-wrapper-opacity", "1");
    }
  }
});

const filterTabs = document.querySelector(".filter-tabs");
const filterButtons = document.querySelectorAll(".filter-button");

filterTabs.addEventListener("click", (event) => {
  const root = document.documentElement;
  const targetTranslateValue = event.target.dataset.translateValue;

  if (event.target.classList.contains("filter-button")) {
    root.style.setProperty("--translate-filters-slider", targetTranslateValue);
    handleActiveTab(filterButtons, event, "filter-active");
  }
});

Thank you for spending your valuable time reading this article. We hope you liked the project.




Video of the Project

                     
                     
                 

Take This Short Survey!


Download Source Code Files

From here You can download the source code files of this Javascript Animated Tab Bar
If you are just starting in web development, these snippets will be useful. We would appreciate it if you would share our blog posts with other like-minded people.


Download Source Code
Please wait ...
If the download didn't start automatically, click here

ByteWebster Play and Win Offer.

PLAY A SIMPLE GAME AND WIN PREMIUM WEB DESIGNS WORTH UPTO $100 FOR FREE.

PLAY FOR FREE





Connect With Us

we would like to keep in touch with you..... Register Here.

JOIN US JOIN TELEGRAM