DEV Community

Cover image for Building CSS Only interactive components from scratch - Part III (tabs)
JoelBonetR 🥇
JoelBonetR 🥇

Posted on • Edited on

Building CSS Only interactive components from scratch - Part III (tabs)

*Each post about Building CSS Only interactive components is stand alone, so you don't need to understand part 1 to understand the part 2. Feel free to check it in the order you want, need or like.
Also a basic understanding about how CSS works is required to understand the workarounds of this posts. If you want to level up your CSS acknowledgement, you can visit this post .


  1. Building CSS Only interactive components from scratch PART 1
  2. Building CSS Only interactive components from scratch PART 2
  3. Building CSS Only interactive components from scratch PART 3

Good morning/evening/night!

Today I'm gonna show you how to create interactive tabs using the same methodology we already saw on part 2 of this post series, the :checked CSS pseudo-selector.

This one is going to be fast to explain.

First, the structure:

  <div class="tab-container">
    <input id="tab-1" type="radio" name="tabs" checked="checked" />
    <input id="tab-2" type="radio" name="tabs" />
    <div class="tabs">
      <label for="tab-1">First Tab</label>
      <label for="tab-2">Second Tab</label>
    </div>
    <div class="tab-content">
      <div class="tab">
        <h3>Lorem Ipsum</h3>
        <p>
          Lorem, ipsum dolor sit amet consectetur 
          adipisicing elit. 
          Laudantium eaque velit molestiae officiis eveniet
          voluptas perferendis autem ab itaque 
          eum asperiores,
          atque nam sequi culpa. Eius ducimus 
          consectetur totam deleniti?
        </p>
      </div>
      <div class="tab">
        <h3>Lorem Ipsum
        <p>
          Lorem, ipsum dolor sit amet consectetur 
          adipisicing elit. 
          Laudantium eaque velit molestiae officiis eveniet
          voluptas perferendis autem ab itaque 
          eum asperiores,
          atque nam sequi culpa. Eius ducimus 
          consectetur totam deleniti?
        </p>
      </div>
    </div>
  </div>

On Part II of this post series we saw the same :checked usage but using checkboxes instead of radio buttons. Radio buttons perform well here as only one can be :checked at a time, so when you click on another one, the current :checked become :not(:checked) and hides again.

You can add as many <div class="tab"> as you need, only make sure that you add a input and a label related to this new tab.

The SCSS:

We begin to set the highlight color we want and the number of tabs on scss variables:

  $tabs: 2;
  $color: #242B36;

Then the input properties.
We need to hide (display: none) the inputs.
Then we iterate through tabs (we set a number above, in this case it's 2) setting some properties when the tab is :checked.
Note that setting correlative numbers inside each input id value helps us to perform this operation.

inside this selectors, we change the display property value from none to inline-block, and the color lines to denote the active one (with a fancy transition as expected).

Of course, we can add these selectors, properties and values about each input:checked and it's childs as many times as we need with plain CSS but using an scss mixin helps us to keep the code cleaner and readable.

input[name="tabs"] {
  display: none;
  @for $i from 1 through $tabs {
    tab-#{$i}:checked {
      ~ .tab-content .tab:nth-of-type(#{$i}) {
        display: inline-block;
      }
      ~ .tabs label:nth-child(#{$i}) {
        color: #242b36;
        &:after {
          width: calc(100% - 40px);
          transition: .3s;
        }
      }
    }
  }
}

All that left is style the .tab-container, the .tabs and the labels:


.tabs {
  box-shadow: 0 5px 5px -5px rgba(0, 0, 0, .3);
  overflow-X: auto;
  -webkit-overflow-scrolling: touch;
  position: relative;
  white-space: nowrap;
  label {
    display: inline-block;
    padding: 18px;
    position: relative;
    color: lighten($color, 60%);
    font-weight: 700;
    font-size: 20px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    cursor: pointer;
    &:after {
      content: '';
      background: #007386;
      width: 0;
      height: 4px;
      position: absolute;
      bottom: 0;
      left: 50%;
      transform: translateX(-50%);
      transition: .1s;
    }
  }
}

.tab-container {
  background: #FFF;
  border-radius: 3px;
  box-shadow: 0 5px 25px -10px rgba(0, 0, 0, .3);
  overflow: hidden;
  .tab {
    display: none;
    padding: 0 20px;
  }
}

You can edit, add or delete loads of properties of this block to make sure it fits your brand design and your design color palette.

It would be kinda tedious to explain each line as much of them are for styling purposes only and have nothing to do with the "CSS only interactive components" purpose.

You can read this post about a complete CSS guide to learn more if you don't know what some property does or means.

By the way i'm letting you the codepen link and embed here so you can fork it and use it as a playground for edit and testing purposes.

Hope it help you to understand more about CSS pseudo-selectors and the potential of CSS3,

see you in the next chapter! =)

Best regards,

Top comments (0)