Chinedu Imoh Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.

How to build a tab component in React

6 min read 1896

Tabs are user interface components that render and display subsections to users; they arrange content into categories for easy access and make your apps look cleaner by saving space. Tabs are a prevalent UI component, and it is essential to understand how to implement them as a developer.

This article will show you how to build a tab component in React and create functions that will handle tab switching.

We will be covering the following:

Prerequisites

To follow along with this tutorial, you’ll need to have Node.Js installed on your machine. You should also have a working knowledge of the following:

  • CSS
  • JavaScript
  • React
  • React Hooks

Setting up a sample project

Let’s set up a new sample project for this tutorial. To get started, we need to create a new project using Create React App. Run the following command in your terminal:

npx create-react-app tab-component-sample

The above command will download all packages that are required to get your React app running.

Next, change your directory into the directory of the newly created app with the below command:

cd tab-component-sample

Use the following code to start up your local development server to view the Create React App sample web app:

npm start

Now, open up a new tab, and render the sample template included in Create React App. If it doesn’t open automatically, open up your browser and enter http://localhost:3000/.

Screenshot of default create react app app

We made a custom demo for .
No really. Click here to check it out.

Creating a tab component

Before we begin creating a component, we need to remove the Create React App boilerplate. In the source folder, find the App.css and Index.css files and clear the styling written there (we will be creating our own).

Open the App.js file, delete everything wrapped inside the div with the app class name, and delete the line that imports the SVG logo:

import logo from './logo.svg';

The App.js file should look like this after the cleanup:

import './App.css';
function App() {
  return (
    <div className="App">             
    </div>
  );
}
export default App;

In your src folder, create a new folder called Components that will house the components we will create. Then create another subfolder called TabComponent, which will house the Tabs.js file:

src
    +-- Components
      +-- TabComponent
        +-- Tabs.js

Now, add the following code to the Tab.js file to show that we are exporting it:

import React from "react";
const Tabs = () => {
  return (
    <div className="Tabs">
      <p>Hello Tab works</p>
    </div>
  );
};
export default Tabs;

Next, we need to import the Tabs.js file into the App.js file:

import "./App.css";
import Tabs from "./Components/TabComponent/Tabs";
function App() {
  return (
    <div className="App">
      <Tabs />
    </div>
  );
}
export default App;

If it’s not displaying on your side, confirm that you are importing the component and exporting it correctly.

Add the following code to your Tabs.js file:

`import React from "react";
const Tabs = () => {
  return (
    <div className="Tabs">
      {/* Tab nav */}
      <ul className="nav">
        <li>Tab 1</li>
        <li>Tab 2</li>
      </ul>
      <div className="outlet">
        {/* content will be shown here */}
      </div>
    </div>
  );
};
export default Tabs;

In the code above we have two sections wrapped in the parent tabs’ div: the nav, and outlet. nav handles the navigation between tabs while outlet will render the contents of the active tab.

It will look ugly when you view it in your browser, and it won’t make any sense, but we’ll add some CSS later.

The next step is to create components for each tab. In this guide we will be creating two.

In the components folder, create a new folder and name it AllTabs. Then, create two files and name them FirstTab.js and SecondTab.js respectively:

src
    +-- Components
      +-- AllTabs
        +-- FirstTab.js
        +-- SecondTab.js

The firstTab.js file contains the code for what needs to be displayed on the first tab, and secondTab.js contains what should be displayed on the second:

// FirstTab.js

import React from "react";
const FirstTab = () => {
  return (
    <div className="FirstTab">
      <p>First Tab!! Hurray!!</p>
      {/* First tab content will go here */}
    </div>
  );
};
export default FirstTab;


// SecondTab.js

import React from "react";
const SecondTab = () => {
  return (
    <div className="SecondTab">
      <p>Second Tab!! Hurray!!</p>
      {/* Second  tab content will go here */}
    </div>
  );
};
export default SecondTab;

That’s all we need for now. Let’s move on to styling.

Styling the tab components

We need to add some styling to what we have created so far. For the sake of this guide, we’ll be writing all styles in the App.css file. You’re free to create separate style files for each component, but don’t forget to import them.

First, let’s remove the default styles the browser adds to our elements, because we want to control the margin and padding ourselves. Using the asterisk selector in CSS, we can select every element on the web app and style them how we please.

We’ll reset all margins and padding to zero, and provide every element a box-sizing of border-box, including all padding and borders to the element’s width:

/* Remove browser defaults */
* {
 box-sizing: border-box;
 padding: 0;
 margin: 0;
}
...

Now let’s style our app.js wrapper. This is a demo app, so it will be a single page that takes the entire width and height of the screen. We also need all elements in the app to be centered in the middle:

// Style App.js wrapper
.App {
 width: 100vw;
 height: 100vh;
 display: flex;
 align-items: center;
 justify-content: center;
 overflow: hidden;
}
...

Next, let’s style our Tabs component. The styling is going to be simple; just add some margins and padding for spacing and a background color to make it look nice:

/* Tab Container */
.Tabs {
 width: 80%;
 height: auto;
 min-height: 400px;
 background: #053742;
 margin: 3.5rem auto 1.5rem;
 padding: 2rem 1rem;
 color: #E8F0F2;
 border-radius: 2rem;
 @media (max-width: 769px) {
  padding: 2rem 0;
 }
}
...

Moving on, we need to distinguish our nav buttons from the tab body so that users can quickly see the navigator and switch between tabs:

/* Tab Navigation */
ul.nav {
  width: 60%;
  margin: 0 auto 2rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid #39A2DB;
  border-radius: 2rem;
  @media (max-width: 768px) {
    width: 90%;
  }
}
ul.nav li {
  width: 50%;
  padding: 1rem;
  list-style: none;
  text-align: center;
  cursor: pointer;
  transition: all 0.7s;
  border-bottom-left-radius: 2rem;
  border-top-left-radius: 2rem;
}
ul.nav li:nth-child(2) {
  border-radius: 0;
  border-bottom-right-radius: 2rem;
  border-top-right-radius: 2rem;
}
ul.nav li:hover {
  background: rgba(50, 224, 196, 0.15);
}
ul.nav li.active {
  background: #39A2DB;
}
...

Finally, let’s style our demo tab content. In this post, we’ll use a p tag element to display dummy data:

/* First and Second Tab Styles */
.FirstTab p,
.SecondTab p {
  font-size: 2rem;
  text-align: center;
}

This is what your final app.css file should look like:

// App.css

/* Remove browser defaults */
* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}
// Style App.js wrapper
.App {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* Tab Container */
.Tabs {
  width: 80%;
  height: auto;
  min-height: 400px;
  background: #053742;
  margin: 3.5rem auto 1.5rem;
  padding: 2rem 1rem;
  color: #E8F0F2;
  border-radius: 2rem;
  @media (max-width: 769px) {
    padding: 2rem 0;
  }

}

/* Tab Navigation */
ul.nav {
  width: 60%;
  margin: 0 auto 2rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid #39A2DB;
  border-radius: 2rem;
  @media (max-width: 768px) {
    width: 90%;
  }
}
ul.nav li {
  width: 50%;
  padding: 1rem;
  list-style: none;
  text-align: center;
  cursor: pointer;
  transition: all 0.7s;
  border-bottom-left-radius: 2rem;
  border-top-left-radius: 2rem;
}
ul.nav li:nth-child(2) {
  border-radius: 0;
  border-bottom-right-radius: 2rem;
  border-top-right-radius: 2rem;
}
ul.nav li:hover {
  background: rgba(50, 224, 196, 0.15);
}
ul.nav li.active {
  background: #39A2DB;
}

/* First and Second Tab Styles */
.FirstTab p,
.SecondTab p {
  font-size: 2rem;
  text-align: center;
}

Reload the page on your browser, and you should see something similar to the image below:

Screenshot of a basic React app with two tabs towards the top of the page that are not separately defined.

Using useState for tab state management

When you go through the styles above, you’ll notice we have a specific style for the active tab, but how do we know which tab is active? For this, we will use the React Hook useState for managing our state. You can read more about React Hooks and state management here.

First, we need to import the useState hook from the React library and set the default active tabs:

import React, { useState } from "react";
const Tabs = () => {
  const [activeTab, setActiveTab] = useState("tab1");
   // ... the previous codes
}
export default Tabs;

Next, we’ll check if the tab is active and add the active class to it. Otherwise, we’ll remove the active class:

// Tab nav       
      <ul className="nav">
        <li className={activeTab === "tab1" ? "active" : ""}>Tab 1</li>
        <li className={activeTab === "tab2" ? "active" : ""}>Tab 2</li>
      </ul>

When you view it from your browser, it should look like this:

Screenshot of basic React app with two tabs at the top; one is highlighted in blue

Tab 1 has a background color because it’s the active tab. Now, let’s tell the React DOM what content to show when a tab is active.

First, we need to import our first and second tab files into the tab component:

import FirstTab from "../AllTabs/FirstTab";
import SecondTab from "../AllTabs/SecondTab";

Then add the imported components to the outlet div:

<div className="outlet">
  <FirstTab />
  <SecondTab />
</div>

When you open your browser, you’ll see a little chaos (the contents of both tabs displayed on Tab 1) but don’t worry, we’ll create order in a bit.

Screenshot of same React app with tabs as before, but with "first tab! Hurray" and "Second tab! Hurray!" written below both tabs

Just like we had a check on the navs to set an active class to the active nav link, we will implement the same approach on the outlet:

<div className="outlet">
  {activeTab === "tab1" ? <FirstTab /> : <SecondTab />}
</div>

What we are doing here is telling the React DOM to show the first tab only when the active tab is "tab1". Otherwise it shows the second tab.

Same React app with tabs as before, but with only "First tab! Hurray!" written below each tab with Tab 1 highlighted in blue

Creating a function to handle tab switching

When you click on any of the tabs, nothing happens. Let’s change that.

This function will tell the React DOM which tab content we want to render when a tab is active:

  //  Functions to handle Tab Switching
  const handleTab1 = () => {
    // update the state to tab1
    setActiveTab("tab1");
  };
  const handleTab2 = () => {
    // update the state to tab2
    setActiveTab("tab2");
  };

This is rather clean and straightforward; you could even write it on a single line, but for simplicity, let’s leave it this way.

So what is the code doing? The first function sets and updates the active tab state to "tab1" anytime it is called, and the second function does the same for "tab2".

The next step is to tag these functions to our nav links in order to be called and executed when the respective nav link is clicked:

{/* Tab nav */}
<ul className="nav">
  <li
    className={activeTab === "tab1" ? "active" : ""}
    onClick={handleTab1}
  >
    Tab 1
  </li>
  <li
    className={activeTab === "tab2" ? "active" : ""}
    onClick={handleTab2}
  >
    Tab 2
  </li>
</ul>

That’s it! Now you can switch tabs by clicking on their respective nav link:

Same React tabs app as before, this time with Tab 2 highlighted in blue with the words "second tab! Hurray!" displayed beneath.

Conclusion

Great job for getting this far! In this guide, we have built a React tab component, used React Hooks to manage our active tab state, and created simple functions to control and handle tab switching.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Chinedu Imoh Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.

Leave a Reply