React Tabs Tutorial: 3 Ways to Implement

Muhammad Syakirurohman
Frontend Engineer
Published on
React Tabs Tutorial: 3 Ways to Implement

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>
	);
}

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';

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>

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>
	);
}

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>
	);
}

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';

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>
	);
}

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!