//PEN HEADER
.header
  h1.header__title Tabs Navigation UI
  .header__btns.btns
    a.header__btn.btn(href="https://github.com/nat-davydova/tab-navigation" title="Check on Github" target="_blanc") Check on Github
    
//PEN CONTENT
.content

  //content title
  h2.content__title Click to any navigation link
  
  //content inner
  .content__inner
    
    //tabs
    .tabs

      //tabs navigation
      .tabs__nav

        ul.tabs__nav-list
          
          li.tabs__nav-item.js-active Profile
          li.tabs__nav-item Settings
          li.tabs__nav-item About Us
          li.tabs__nav-item FAQ
          
    
      //tabs panels
      .tabs__panels
      
        //single panel
        .tabs__panel
        
          .tabs__panel-card
            .tabs__panel-avatar
            .tabs__panel-content
          
          .tabs__panel-card
            .tabs__panel-content
            
          .tabs__panel-card
            .tabs__panel-content
        
        //single panel
        .tabs__panel
        
          .tabs__panel-card
            .tabs__panel-content
            .tabs__panel-content
            
          .tabs__panel-card
            .tabs__panel-content
            
          .tabs__panel-card.tabs__panel-card--spaced-between
            .tabs__panel-img
            .tabs__panel-img
            .tabs__panel-img
        
        //single panel
        .tabs__panel
        
          .tabs__panel-card
            .tabs__panel-content
            
          .tabs__panel-card
            .tabs__panel-content
            .tabs__panel-img
            
          .tabs__panel-card
            .tabs__panel-img
            .tabs__panel-content
        
        //single panel
        .tabs__panel
        
          .tabs__panel-card
            .tabs__panel-content
            .tabs__panel-content
            
          .tabs__panel-card
            .tabs__panel-content
            
          .tabs__panel-card
            .tabs__panel-content
            .tabs__panel-content
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;
}

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


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

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

.btn {
  @include transition-mix;
  
  padding: 10px 20px;
  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: 500px;
  margin: 50px auto;
  
  text-align: center;
}

.header__title {
  margin-bottom: 30px;
  
  font: {
    weight: 500;
  }
}

//content styles
.content {
  max-width: 700px;
  margin: auto;
}

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

.content__inner {
  width: 375px;
  height: 550px;
  
  margin: auto;
  
  box-shadow: 
    0 8px 17px 2px rgba(0,0,0,0.14), 
    0 3px 14px 2px rgba(0,0,0,0.12), 
    0 5px 5px -3px rgba(0,0,0,0.2);
}

//tabs styles
$tabs-padding: 15px;

.tabs {
  position: relative;
  
  padding: $tabs-padding;
  height: 100%;
  
  overflow: hidden;
}

//tabs nav styles
$theme-accent-color: #119DA4;

.tabs__nav {
  position: relative;
}

//nav decoration is appended by js
.tabs__nav-decoration {
  position: absolute;
  top: 0;
  left: 0;
  
  height: 100%;
  
  transition: width .2s linear 0s,
              transform .2s ease-out 0s;
  
  background-color: $theme-accent-color;
  border-radius: 3px;
  
  z-index: 1;
}

.tabs__nav-list {
  position: relative;
  
  display: flex;
  justify-content: space-between;
  
  list-style-type: none;
  
  z-index: 5;
}

.tabs__nav-item {
  @include transition-mix($delay: 0s);
  
  padding: 15px;
  
  cursor: pointer;
  
  //active styles
  &.js-active {
    @include transition-mix($delay: .05s);
    color: #fff;
  }
}

$panels-bg-color: rgba(0,0,0,.15);

.tabs__panels {
  position: relative;
  
  margin-top: 30px;
}

.tabs__panel {
  @include position-absolute($top: 0, $left: 0);
  
  transition: none;
  
  transform: scale(.8);
  
  width: 100%;
  
  opacity: 0;
  
  //active panel styles
  &.js-active {
    transition: all .25s linear 0s;
    
    transform: scale(1);
    
    opacity: 1;
  }
}

.tabs__panel-card {
  display: flex;
  margin-bottom: 30px;
  padding: 15px;
  
  box-shadow: 
    0 2px 2px 0 rgba(0,0,0,0.14), 
    0 3px 1px -2px rgba(0,0,0,0.12), 
    0 1px 5px 0 rgba(0,0,0,0.2);
  
  &:last-child {
    margin-bottom: 0;
  }
}

.tabs__panel-card--spaced-between {
  justify-content: space-between;
}

.tabs__panel-avatar {
  flex-shrink: 0;
  width: 100px;
  height: 100px;
  
  border-radius: 50%;
  background-color: $panels-bg-color;
}

.tabs__panel-img {
  flex-shrink: 0;
  width: 80px;
  height: 80px;
  
  border-radius: 4px;
  background-color: $panels-bg-color;
}

.tabs__panel-content {
  width: 100%;
  margin-left: 30px;
  
  &:first-child {
    margin-left: 0;
  }
  
  &:not(:last-child) {
    margin-right: 30px;
  }
  
  &:before,
  &:after {
    display: block;
    width: 100%;
    height: 20px;
    
    content: '';
    
    background-color: $panels-bg-color;
  }
  
  &:before {
    margin-bottom: 15px;
  }
  
}
View Compiled
const DOM = {
  tabsNav: document.querySelector('.tabs__nav'),
  tabsNavItems: document.querySelectorAll('.tabs__nav-item'),
  panels: document.querySelectorAll('.tabs__panel')
};

//set active nav element
const setActiveItem = elem => {
  
  DOM.tabsNavItems.forEach(el => {
    
    el.classList.remove('js-active');
    
  });
  
  elem.classList.add('js-active');
  
};

//find active nav element
const findActiveItem = () => {
  
  let activeIndex = 0;
  
  for(let i = 0; i < DOM.tabsNavItems.length; i++) {
    
    if (DOM.tabsNavItems[i].classList.contains('js-active')) {
      activeIndex = i;
      break;
    };
    
  };
  
  return activeIndex;
  
};

//find active nav elements parameters: left coord, width
const findActiveItemParams = (activeItemIndex) => {
  
  const activeTab = DOM.tabsNavItems[activeItemIndex];
  
  //width of elem
  const activeItemWidth = activeTab.offsetWidth - 1;
  
  //left coord in the tab navigation
  const activeItemOffset_left = activeTab.offsetLeft;
  
  return [activeItemWidth, activeItemOffset_left];
  
};

//appending decoration block to an active nav element
const appendDecorationNav = () => {
  
  //creating decoration element
  let decorationElem = document.createElement('div');
  
  decorationElem.classList.add('tabs__nav-decoration');
  decorationElem.classList.add('js-decoration');
  
  //appending decoration element to navigation
  DOM.tabsNav.append(decorationElem); 
  
  //appending styles to decoration element
  return decorationElem;
};

//appending styles to decoration nav element
const styleDecorElem = (elem, decorWidth, decorOffset) => {
  elem.style.width = `${decorWidth}px`;
  elem.style.transform = `translateX(${decorOffset}px)`;
};

//find active panel
const findActivePanel = index => {
  
  return DOM.panels[index];
  
};

//set active panel class
const setActivePanel = index => {
  
  DOM.panels.forEach(el => {
    
    el.classList.remove('js-active');
    
  });
  
  DOM.panels[index].classList.add('js-active');
  
};

//onload function
window.addEventListener('load', () => {
  
  //find active nav item
  const activeItemIndex = findActiveItem();
  
  //find active nav item params
  const [decorWidth, decorOffset] = findActiveItemParams(activeItemIndex);
  
  //appending decoration element to an active elem
  const decorElem = appendDecorationNav();
  
  //setting styles to the decoration elem
  styleDecorElem(decorElem, decorWidth, decorOffset);
  
  //find active panel
  findActivePanel(activeItemIndex);
  
  //set active panel
  setActivePanel(activeItemIndex);
});

//click nav item function
DOM.tabsNav.addEventListener('click', e => {
  
  const navElemClass = 'tabs__nav-item';
  
  //check if we click on a nav item
  if(e.target.classList.contains(navElemClass)) {
    
    const clickedTab = e.target;
    
    const activeItemIndex = Array.from(DOM.tabsNavItems).indexOf(clickedTab);
    
    //set active nav item
    setActiveItem(clickedTab);
    
    //find active nav item
    const activeItem = findActiveItem();

    //find active nav item params
    const [decorWidth, decorOffset] = findActiveItemParams(activeItem);
    
    //setting styles to the decoration elem
    const decorElem = document.querySelector('.js-decoration');
    
    styleDecorElem(decorElem, decorWidth, decorOffset);
    
    //find active panel
    findActivePanel(activeItemIndex);
  
    //set active panel
    setActivePanel(activeItemIndex);
    
  }
  
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.