DEV Community

Cover image for React Tabs Tutorial: 3 Ways to Implement
Syakir
Syakir

Posted on • Edited on • Originally published at devaradise.com

React Tabs Tutorial: 3 Ways to Implement

This post was originally published at https://www.devaradise.com/react-tabs-tutorial

Tab is a common component in web applications that organize content in different views. Tabs allow us to break up complex interfaces into more manageable subsections that a user can quickly switch between.

In a React project, we can implement tabs component in many ways. In this post, I am going to show you how to implement react tabs using 3 different ways, with the demo examples.

We will create a manual tabs component using react state hooks, a routed react tabs using react-router-dom, and easy React tabs component using react-tabs library.

With these 3 different ways, I hope you find the right way to implement tabs component that suits your project.

Before we begin, as always, I assume that youโ€™re already know how to initialize a react project using create-react-app because I wonโ€™t explain it anymore.

I also use functional component and Hooks to manage state in the component as it is more simple and cleaner than using class-based component.

How to Implement React Tabs with State Hooks

Implementing react tabs using state hooks is suitable if you don't want to use any tabs library. You just want to create a simple tabs component that managed by useState() hook.

Here is how to implement it.

import React, { useState } from 'react'

export default function WithStateHook() {

  const [currentTab, setCurrentTab] = useState('tab1');
  const tabList = [
    {
      name: 'tab1',
      label: 'Tab 1',
      content: (
        <div className="tab-content">
          <h2>Tab content 1</h2>
          <p>Here is your tab content. You can separate this as a component.</p>
          <p>Lorem ipsum dolor sit amet ...</p>
        </div>
      )
    },
    {
      name: 'tab2',
      label: 'Tab 2',
      content: (
        <div className="tab-content">
          <h2>Tab content 2</h2>
          <p>Here is your tab content. You can separate this as a component.</p>
          <p>Lorem ipsum dolor sit amet ...</p>
        </div>
      )
    },
    {
      name: 'tab3',
      label: 'Tab 3',
      content: (
        <div className="tab-content">
          <h2>Tab content 3</h2>
          <p>Here is your tab content. You can separate this as a component.</p>
          <p>Lorem ipsum dolor sit amet ...</p>
        </div>
      )
    }
  ];

  return (
    <div className="simple-tabs">

      <h1>With State Hook</h1>

      <div className="tabs">
        {
          tabList.map((tab, i) => (
            <button 
              key={i}
              onClick={() => setCurrentTab(tab.name)} 
              className={(tab.name === currentTab) ? 'active' : ''}>
                {tab.label}
            </button>
          ))
        }
      </div>

      {
        tabList.map((tab, i) => {
          if(tab.name === currentTab) {
            return <div key={i}>{tab.content}</div>;
          } else {
            return null;
          }
        })
      }
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

With using state hook, the simplest way I found to implement tabs component is by declaring a currentTab state and a tabList variable that stores all tab data in an array.

The logic is simple. You just loop the tabList and show the only tab that has matched name value with currentTab value.

The currentTab value will changes as the user clicks a tab. It handled in onClick event attribute in tab markup.

I use button tag for the tab because when I use a tag without href or with invalid href value (#), it returns an error from eslint-plugin-jsx.

I tried to resolve error with eslint-disable-next-line and it works. But, when i built it, the tabs component doesn't render.

I think, React is encouraging us to follow that rule. So, i just follow them.

Back to the codes, you can change the tabList to become a react prop or state if you want to make it dynamic.

For instance, if you want to make this tab component reusable and shared in your project, you can make the tabList as a prop. So, you can pass the tabList value from any component in your project.

If you want to see the demo you can click this link. As for the codes, you can clone my react-lab repository on github. It contains all demo examples for all react tutorials I wrote in this blog.

How to Implement Routed React Tabs with react-router-dom

Routed tabs component means that each tab has its own route / URL. When a tab clicked, the route will changes. So, this is the best choice if you care about SEO, or simply just want to directly access a tab via URL.

You can implement a routed tabs component using react-router-dom, a popular router library for React.

Before creating a routed tabs component, make sure you install react-router-dom first in your project.

npm install react-router-dom

After that, you should import react-router-dom in your component like this.

import { Route, Switch, NavLink } from 'react-router-dom'
Enter fullscreen mode Exit fullscreen mode

You should also make sure that your component or its parent component are wrapped inside BrowserRouter because Route only works inside BrowserRouter.

<BrowserRouter>
  <Route exact component={Home} path="/"/>
  <Route component={ReactTabs} path="/react-tabs-component"/>
</BrowserRouter>
Enter fullscreen mode Exit fullscreen mode

Usually, BrowserRouter added in root component like App.js.

Then, you can implement the codes below.

Simple Implementation

For this simple implementation, you can just use repeated NavLink for tab menu, Route for tab content, and Switch to make it work as tabs.

import React from 'react'
import { Route, Switch, NavLink } from 'react-router-dom'

export default function RoutedTabs(props) {
  const parentPath = props.match.path;

  return (
    <div className="routed-tabs">
      <h1>Routed Tabs</h1>
      <div className="tabs">
        <NavLink
          to={parentPath+'/tab-1'}
          activeClassName="active"
          isActive={(match, location) =>
              [parentPath, parentPath+'/tab-1'].includes(location.pathname)
          }
        >
          Tab 1
        </NavLink>
        <NavLink
          to={parentPath+'/tab-2'}
          activeClassName="active"
          isActive={(match, location) =>
              [parentPath+'/tab-2'].includes(location.pathname)
          }
        >
          Tab 2
        </NavLink>
        <NavLink
          to={parentPath+'/tab-3'}
          activeClassName="active"
          isActive={(match, location) =>
              [parentPath+'/tab-3'].includes(location.pathname)
          }
        >
          Tab 3
        </NavLink>
      </div>

      <Switch>
        <Route component={
          () => (<div className="tab-content">
            <h2>Tab content 1</h2>
            <p>Here is your tab content. You can separate this as a component.</p>
            <p>Lorem ipsum dolor sit amet ...</p>
          </div>)
        } exact path={[parentPath, parentPath+"/tab-1"]}/>

        <Route component={
          () => (<div className="tab-content">
            <h2>Tab content 2</h2>
            <p>Here is your tab content. You can separate this as a component.</p>
            <p>Lorem ipsum dolor sit amet ...</p>
          </div>)
        } path={[parentPath+"/tab-2"]}/>

        <Route component={
          () => (<div className="tab-content">
            <h2>Tab content 3</h2>
            <p>Here is your tab content. You can separate this as a component.</p>
            <p>Lorem ipsum dolor sit amet ...</p>
          </div>)
        } path={[parentPath+"/tab-3"]}/>

      </Switch>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the codes above don't have much logic as it's for static tabs.

If you want to make a dynamic tabs component like when we implement tabs using state hook, you can see the codes below.

Dynamic Implementation

import React from 'react'
import { Route, Switch, NavLink } from 'react-router-dom'

export default function RoutedTabsDynamic(props) {
  const parentPath = props.match.path;

  const tabsData = [
    {
      label: "Tab 1",
      path: parentPath+"/tab-1",
      content: (<div className="tab-content">
        <h2>Tab content 1</h2>
        <p>Here is your tab content. You can separate this as a component.</p>
        <p>Lorem ipsum dolor sit amet ...</p>
      </div>),
      defaultTab: true
    },
    {
      label: "Tab 2",
      path: parentPath+"/tab-2",
      content: (<div className="tab-content">
        <h2>Tab content 2</h2>
        <p>Here is your tab content. You can separate this as a component.</p>
        <p>Lorem ipsum dolor sit amet ...</p>
      </div>),
    },
    {
      label: "Tab 3",
      path: parentPath+"/tab-3",
      content: (<div className="tab-content">
        <h2>Tab content 3</h2>
        <p>Here is your tab content. You can separate this as a component.</p>
        <p>Lorem ipsum dolor sit amet ...</p>
      </div>),
    }
  ]


  return (
    <div className="routed-tabs">
      <h1>Routed Tabs</h1>
      <div className="tabs">

        {tabsData.map((data, i) => {
          return (
            <NavLink
              key={i}
              to={data.path}
              activeClassName="active"
              isActive={(match, location) =>
                data.defaultTab
                  ? [parentPath, data.path].includes(location.pathname)
                  : [data.path].includes(location.pathname)
              }
            >
              {data.label}
            </NavLink>
          );
        })}

      </div>

      <Switch>
        {tabsData.map((data, i) => {
          return (
            <Route 
              key={i}
              component={() => data.content} 
              exact 
              path={
                data.defaultTab
                  ? [parentPath, data.path]
                  : [data.path]
              }
            />
          );
        })}
      </Switch>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

The logic is the same with the implementation using state hook. The differences are just the markup to be looped.

To see the working demo for routed react tabs, you can click the link below.

Live Demo

How to Implement React Tabs with react-tabs library

The last way to implement react tabs is by using a library. There are a lot of tabs libraries for React out there. But here, we're going to use react-tabs.

First, you should install it on your project.

npm install react-tabs

Then, import react-tabs to your component like below. You should also import the CSS as react-tabs has pre-defined style.

import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import 'react-tabs/style/react-tabs.css';
Enter fullscreen mode Exit fullscreen mode

For full implementation of react-tabs, you can see the following codes.

import React from 'react'
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'
import 'react-tabs/style/react-tabs.css'

export default function WithReactTabs() {
  return (
    <div className="with-react-tabs">
      <h1>With react-tabs</h1>

      <Tabs>
        <TabList>
          <Tab>Tab 1</Tab>
          <Tab>Tab 2</Tab>
          <Tab>Tab 3</Tab>
        </TabList>

        <TabPanel>
          <div className="tab-content">
            <h2>Tab content 1</h2>
            <p>Here is your tab content. You can separate this as a component.</p>
            <p>Lorem ipsum dolor sit amet ...</p>
          </div>
        </TabPanel>
        <TabPanel>
          <div className="tab-content">
            <h2>Tab content 2</h2>
            <p>Here is your tab content. You can separate this as a component.</p>
            <p>Lorem ipsum dolor sit amet ...</p>
          </div>
        </TabPanel>
        <TabPanel>
          <div className="tab-content">
            <h2>Tab content 3</h2>
            <p>Here is your tab content. You can separate this as a component.</p>
            <p>Lorem ipsum dolor sit amet ...</p>
          </div>
        </TabPanel>
      </Tabs>

    </div> 
  )
}
Enter fullscreen mode Exit fullscreen mode

That is just a static tabs implementation. If you want to make it dynamic, just follow the mechanism in the tabs component with state hook or routed tabs. The logic is the same.

That's all. I hope this helpful.

If you want to see similar react tutorials, you might interested with these:

Happy coding!

Top comments (1)

Collapse
 
gedalyakrycer profile image
Gedalya Krycer

Nice!