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>
);
};
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:
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;
}
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";
const Tab = () => {
const [toggleState, setToggleState] = useState(1)
return (
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)
}
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>
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>
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>
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 : "";
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;
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:
Top comments (2)
Nice article. Checkout the aria tab role to add accessibility! developer.mozilla.org/en-US/docs/W...
Oh, thank you :) I will check that!