DEV Community

The Huferr
The Huferr

Posted on

TAB Component with ReactJS

Welcome, my name is Hugo Ferreira! Today, I'm here to teach you how to create a TAB component with ReactJS!

Observation: I created this post considering that you know the basics of ReactJS. If you see anything wrong, please tell me!

You can see it working at CodePen: https://codepen.io/huferr/pen/GRmZJJx

To do this, we will use a functional component called Tab. This component will return the HTML content. Let's define it:

const Tab = () => {
  return (
    <div className="container">
      <ul className="tab-list">
        <li className="tabs active-tabs">Tab 1</li>
        <li className="tabs">Tab 2</li>
        <li className="tabs">Tab 3</li>
      </ul>
      <div className="content-container">
        <div className="content active-content"><h2>Lorem</h2></div>
        <div className="content"><h2>Ipsum</h2></div>
        <div className="content"><h2>Dolor</h2></div>
      </div>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Observe the classes called active-tabs and active-content in our first tab and content elements. These classes will define which component should or should not be shown, and we'll use CSS to make this happen.

What will make the tab change effect is the active-tabs class. When called, the style of the tab will change, making it "visible". Look the example:

Tab component

Here's the CSS file:

.container {
  width: 400px;
  height: 250px;
  background-color: #eeeded;
  border: 1px solid rgba(0, 0, 0, 0.3);
}

.tab-list {
  height: 50px;
  display: flex;
  list-style: none;
  font-size: 18px;
  padding: 0;
  margin: 0;
}

.tabs {
  width: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #80808013;
  position: relative;
  cursor: pointer;
}

.tabs:not(:last-child) {
  border-right: 1px solid rgba(0, 0, 0, 0.3);
}

.active-tabs {
  background: #eeeded;
}

.active-tabs::before {
  content: "";
  display: block;
  position: absolute;
  top: -4px;
  left: 50%;
  transform: translateX(-50%);
  width: calc(100% + 2px);
  height: 4px;
  background: #5893f1;
}

.content {
    display: none;
    background-color: #eeeded;
    padding: 10px;
}

.active-content {
    display: flex;
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the tabs class has a background to represent that it has not been selected. So, when we put the active-tabs class, the tab style looks like it's selected.

Looking at the content class, we can see display: none, which will "hide" the content from the screen, and it will only show when we call active-content, which has display: flex. This will make the content appear.

What we have to do now is create a way to control these classes when we click on each tab, binding the element that has the active-tabs class with the element that has the active-content class.

To do that, let's import useState Hook and set our toggleState, which will handle the index of each tab we have.

Obs.: Do it in the same Tab component.

import React, { useState } from "react";
Enter fullscreen mode Exit fullscreen mode
const Tab = () => {

    const [toggleState, setToggleState] = useState(1)

  return (
Enter fullscreen mode Exit fullscreen mode

Now, let's define an Index for each tab we have (3).

// Tab 1 = index 1
// Tab 2 = index 2, and so on...

To make it easier to understand, let's create a function that will set the index every time we click in each tab:

const toggleTab = (index) = {
        setToggleState(index)
    }
Enter fullscreen mode Exit fullscreen mode

Then, create an onClick event on each tab. Call an anonymous function with our toggleTab function. So, for each tab, let's define an index:

<ul className="tab-list">
        <li className="tabs active-tabs" onClick={() => toggleTab(1)}>Tab 1</li>
        <li className="tabs"onClick={() => toggleTab(2)}>Tab 2</li>
        <li className="tabs"onClick={() => toggleTab(3)}>Tab 3</li>
      </ul>
Enter fullscreen mode Exit fullscreen mode

Finally, let's control the classes! For this, let's use a ternary operator inside className="":

 <ul className="tab-list">
        <li className={toggleState === 1 ? 'tabs active-tabs' : "tabs"} onClick={() => toggleTab(1)}>Tab 1</li>
        <li className={toggleState === 2 ? 'tabs active-tabs' : "tabs"} onClick={() => toggleTab(2)}>Tab 2</li>
        <li className={toggleState === 3 ? 'tabs active-tabs' : "tabs"} onClick={() => toggleTab(3)}>Tab 3</li>
      </ul>
Enter fullscreen mode Exit fullscreen mode

Now, let's do it for the content:

<div className="content-container">
        <div className={toggleState === 1 ? 'content active-content' : "content"}><h2>Lorem</h2></div>
        <div className={toggleState === 2 ? 'content active-content' : "content"}><h2>Ipsum</h2></div>
        <div className={toggleState === 3 ? 'content active-content' : "content"}><h2>Dolor</h2></div>
      </div>
Enter fullscreen mode Exit fullscreen mode

Basically, we are saying that if toggleState is 1, put the class tabs and active-tabs in the Tab 1. if toggleState is 2, put the class tabs and active-tabs in the Tab 2. If not, put only tabs Same for the content classes.

In order to make it better, let's create a function to do this comparison:

const getActiveClass = (index, className) =>
    toggleState === index ? className : "";
Enter fullscreen mode Exit fullscreen mode

Overview:

import React, { useState } from "react";
import "./styles.css";

const Tab = () => {
  const [toggleState, setToggleState] = useState(1);

  const toggleTab = (index) => {
    setToggleState(index);
  };

  const getActiveClass = (index, className) =>
    toggleState === index ? className : "";

  return (
    <div className="container">
      <ul className="tab-list">
        <li
          className={`tabs ${getActiveClass(1, "active-tabs")}`}
          onClick={() => toggleTab(1)}
        >
          Tab 1
        </li>
        <li
          className={`tabs ${getActiveClass(2, "active-tabs")}`}
          onClick={() => toggleTab(2)}
        >
          Tab 2
        </li>
        <li
          className={`tabs ${getActiveClass(3, "active-tabs")}`}
          onClick={() => toggleTab(3)}
        >
          Tab 3
        </li>
      </ul>
      <div className="content-container">
        <div className={`content ${getActiveClass(1, "active-content")}`}>
          <h2>Lorem</h2>
        </div>
        <div className={`content ${getActiveClass(2, "active-content")}`}>
          <h2>Ipsum</h2>
        </div>
        <div className={`content ${getActiveClass(3, "active-content")}`}>
          <h2>Dolor</h2>
        </div>
      </div>
    </div>
  );
};

export default Tab;

Enter fullscreen mode Exit fullscreen mode

Results

Results

Done! Thanks for reading this content, I hope it helps you in some way and, if you notice something wrong, feel free to help me leaving a comment bellow or find me on twitter !

You can also find me at:

Github
Linkedin

Top comments (2)

Collapse
 
makhbeth_25 profile image
Davide Di Pumpo

Nice article. Checkout the aria tab role to add accessibility! developer.mozilla.org/en-US/docs/W...

Collapse
 
thehuferr profile image
The Huferr

Oh, thank you :) I will check that!