MUI (Material-UI) Tabs Navigation is a React component from the Material-UI library that provides a way to create tabbed interfaces. We will use the MUI library to implement Tab navigation in React 18.2.
Tabs are the best UI element for navigating between different views or components within the same context. They make it easy to explore and switch between different views.
You can implement Tabs using a collection of related components:
- <Tab />: It is a tab element itself. If you click on a tab, its corresponding panel will be displayed.
- <Tabs />: It is a container that houses the tabs. It is responsible for handling focus and keyboard navigation between tabs.
Here is a step-by-step guide:
Step 1: Setup React.js project
Vite is a blazing-fast frontend bundler that creates highly optimized builds. We will use Vite to create a new React.js project.
Type the following command to create a basic project boilerplate:
npm create vite@latest tabs-app -- --template react
Go inside the tabs-app folder:
cd tabs-app
Install the necessary project dependencies:
npm install
Step 2: Installing MUI
Install MUI using the below command:
npm install @mui/material @emotion/react @emotion/styled
To make the code more modular and efficient, we can break it down into smaller components and reuse them.
Step 3: TabPanel Component
Create a separate TabPanel.jsx component inside the src folder. This is a reusable component which we will use the different types of tabs later in this post.
Add the below code in the TabPanel.jsx file:
// TabPanel.jsx import { Box, Typography } from "@mui/material"; function TabPanel(props) { // eslint-disable-next-line react/prop-types const { children, value, index, ...other } = props; return ( <div role="tabpanel" hidden={value !== index} id={`tabpanel-${index}`} aria-labelledby={`tab-${index}`} {...other} > {value === index && ( <Box p={3}> <Typography>{children}</Typography> </Box> )} </div> ); } export default TabPanel;
In this code, we defined a functional TabPanel component designed to display the content of a tab panel.
We defined the TabPanel component for use within a tab navigation system. It conditionally displays its content based on the active tab (value and index), ensuring that only the content for the active tab is visible.
Step 4: Tabs Component
Create a TabsContainer component for managing tabs inside the src folder:
// TabsContainer.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function TabsContainer() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="tabs example" > <Tab label="Item One" {...a11yProps(0)} /> <Tab label="Item Two" {...a11yProps(1)} /> <Tab label="Item Three" {...a11yProps(2)} /> </Tabs> <TabPanel value={tabValue} index={0}> Item One </TabPanel> <TabPanel value={tabValue} index={1}> Item Two </TabPanel> <TabPanel value={tabValue} index={2}> Item Three </TabPanel> </div> ); } export default TabsContainer;
Step 5: Main App.jsx Component
We created the TabsContainer component. Import that component inside the src/App.jsx file like this:
// App.jsx import TabsContainer from "./components/TabsContainer"; const App = () => ( <div> <TabsContainer /> </div> ); export default App;
Save the file and start the development server using this command:
npm run dev
Go to this URL: http://localhost:5173/
If you click on different tabs, you will get different views based on that tab. By breaking the code into small modular pieces, we achieve better separation of concerns and enhance code reusability.
Tabs Navigation Variants
Wrapped labels
If the label is too long for the tab in your project, it will automatically be wrapped.
Create a new file called WrappedLabelsTabs.jsx inside the src folder and add the below code:
// WrappedLabelsTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function WrappedLabelsTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="wrapped label tabs" > <Tab label="Short Label" {...a11yProps(0)} /> <Tab label="Very Long Label That Will Wrap" {...a11yProps(1)} /> <Tab label="Another Short Label" {...a11yProps(2)} /> </Tabs> <TabPanel value={tabValue} index={0}> Item One </TabPanel> <TabPanel value={tabValue} index={1}> Item two </TabPanel> <TabPanel value={tabValue} index={2}> Item three </TabPanel> </div> ); } export default WrappedLabelsTabs;
Import the WrappedLabelsTabs.jsx component inside the App.jsx component:
// App.jsx import WrappedLabelsTabs from "./components/WrappedLabelsTabs"; const App = () => ( <div> <WrappedLabelsTabs /> </div> ); export default App;
Save the file, and the output looks like the below image:
Colored Tabs
You can customize the tab colors to match the design theme.
Create a new file called ColoredTabs.jsx inside the src folder and add the below code:
// ColoredTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function ColoredTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="colored tabs example" textColor="secondary" indicatorColor="secondary" > <Tab label="Tab One" {...a11yProps(0)} /> <Tab label="Tab Two" {...a11yProps(1)} /> <Tab label="Tab Three" {...a11yProps(2)} /> </Tabs> <TabPanel value={tabValue} index={0}> Content One </TabPanel> <TabPanel value={tabValue} index={1}> Content Two </TabPanel> <TabPanel value={tabValue} index={2}> Content Three </TabPanel> </div> ); } export default ColoredTabs;
Import the ColoredTabs.jsx component inside the App.jsx component:
// App.jsx import ColoredTabs from "./components/ColoredTabs"; const App = () => ( <div> <ColoredTabs /> </div> ); export default App;
Output
Disabled Tabs
In an actual project, we must disable some tabs based on the user’s role or permission. You can use the option to disable specific tabs to prevent user interaction.
Create a new file called DisabledTabs.jsx inside the src folder and add the below code:
// DisabledTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function DisabledTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="disabled tabs example" > <Tab label="Active Tab" {...a11yProps(0)} /> <Tab label="Disabled Tab" disabled {...a11yProps(1)} /> <Tab label="Another Active Tab" {...a11yProps(2)} /> </Tabs> <TabPanel value={tabValue} index={0}> Content One </TabPanel> <TabPanel value={tabValue} index={1}> Disabled Content </TabPanel> <TabPanel value={tabValue} index={2}> Content Three </TabPanel> </div> ); } export default DisabledTabs;
Import the DisabledTabs.jsx component inside the App.jsx component:
// App.jsx import DisabledTabs from "./components/DisabledTabs"; const App = () => ( <div> <DisabledTabs /> </div> ); export default App;
Output
Fixed Tabs
You can fix the width of the tab to create a consistent layout throughout your React project.
Create a new file called FixedTabs.jsx inside the src folder and add the below code:
// FixedTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function FixedTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="fixed tabs example" variant="fullWidth" > <Tab label="Fixed Tab One" {...a11yProps(0)} /> <Tab label="Fixed Tab Two" {...a11yProps(1)} /> <Tab label="Fixed Tab Three" {...a11yProps(2)} /> </Tabs> <TabPanel value={tabValue} index={0}> Content One </TabPanel> <TabPanel value={tabValue} index={1}> Content Two </TabPanel> <TabPanel value={tabValue} index={2}> Content Three </TabPanel> </div> ); } export default FixedTabs;
Import the FixedTabs.jsx component inside the App.jsx component:
// App.jsx import FixedTabs from "./components/FixedTabs"; const App = () => ( <div> <FixedTabs /> </div> ); export default App;
Output
Scrollable Tabs
You can create scrollable tabs to handle many tabs within limited space.
Create a new file called ScrollableTabs.jsx inside the src folder and add the below code:
// ScrollableTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function ScrollableTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="scrollable tabs example" variant="scrollable" scrollButtons="auto" > <Tab label="Item One" {...a11yProps(0)} /> <Tab label="Item Two" {...a11yProps(1)} /> <Tab label="Item Three" {...a11yProps(2)} /> <Tab label="Item Four" {...a11yProps(3)} /> <Tab label="Item Five" {...a11yProps(4)} /> <Tab label="Item Six" {...a11yProps(5)} /> <Tab label="Item Seven" {...a11yProps(6)} /> </Tabs> <TabPanel value={tabValue} index={0}> Content One </TabPanel> <TabPanel value={tabValue} index={1}> Content Two </TabPanel> <TabPanel value={tabValue} index={2}> Content Three </TabPanel> <TabPanel value={tabValue} index={3}> Content Four </TabPanel> <TabPanel value={tabValue} index={4}> Content Five </TabPanel> <TabPanel value={tabValue} index={5}> Content Six </TabPanel> <TabPanel value={tabValue} index={6}> Content Seven </TabPanel> </div> ); } export default ScrollableTabs;
Import the ScrollableTabs.jsx component inside the App.jsx component:
// ScrollableTabs.jsx import ScrollableTabs from "./components/ScrollableTabs"; const App = () => ( <div> <ScrollableTabs /> </div> ); export default App;
Output
Customizable Tabs
You can customize the appearance and behavior of tabs.
Create a new file called CustomizedTabs.jsx inside the src folder and add the below code:
// CustomizedTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import { styled } from "@mui/system"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } const CustomTabs = styled(Tabs)({ "& .MuiTabs-indicator": { backgroundColor: "#FF0000", }, }); const CustomTab = styled((props) => <Tab {...props} />)(({ theme }) => ({ "&:hover": { backgroundColor: "#FFFFFF", color: "#000000", }, })); function CustomizedTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <CustomTabs value={tabValue} onChange={handleTabChange} aria-label="customized tabs example" > <CustomTab label="Custom Tab One" {...a11yProps(0)} /> <CustomTab label="Custom Tab Two" {...a11yProps(1)} /> <CustomTab label="Custom Tab Three" {...a11yProps(2)} /> </CustomTabs> <TabPanel value={tabValue} index={0}> Custom Content One </TabPanel> <TabPanel value={tabValue} index={1}> Custom Content Two </TabPanel> <TabPanel value={tabValue} index={2}> Custom Content Three </TabPanel> </div> ); } export default CustomizedTabs;
Import the CustomizedTabs.jsx component inside the App.jsx component:
// App.jsx import CustomizedTabs from "./components/CustomizedTabs"; const App = () => ( <div> <CustomizedTabs /> </div> ); export default App;
Output
Vertical Tabs
You can align tabs to Vertical for use cases with limited horizontal space.
Create a new file called VerticalTabs.jsx inside the src folder and add the below code:
// VerticalTabs.jsx import React from "react"; import { Tabs, Tab, Box, Typography } from "@mui/material"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function VerticalTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <Box display="flex"> <Tabs orientation="vertical" value={tabValue} onChange={handleTabChange} aria-label="vertical tabs example" sx={{ borderRight: 1, borderColor: "divider" }} > <Tab label="Vertical Tab One" {...a11yProps(0)} /> <Tab label="Vertical Tab Two" {...a11yProps(1)} /> <Tab label="Vertical Tab Three" {...a11yProps(2)} /> </Tabs> <Box p={3}> {tabValue === 0 && <Typography>Vertical Content One</Typography>} {tabValue === 1 && <Typography>Vertical Content Two</Typography>} {tabValue === 2 && <Typography>Vertical Content Three</Typography>} </Box> </Box> ); } export default VerticalTabs;
Import the VerticalTabs.jsx component inside the App.jsx component:
// App.jsx import VerticalTabs from "./components/VerticalTabs"; const App = () => ( <div> <VerticalTabs /> </div> ); export default App;
Output
Nav Tabs
You can use the tabs to navigate between different routes or views.
You need to install the react-router-dom library using this command:
npm install react-router-dom
Create a new file called NavTabs.jsx inside the src folder and add the below code:
// NavTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function NavTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <Router> <Tabs value={tabValue} onChange={handleTabChange} aria-label="nav tabs example" > <Tab label="Nav One" component={Link} to="/nav-one" {...a11yProps(0)} /> <Tab label="Nav Two" component={Link} to="/nav-two" {...a11yProps(1)} /> <Tab label="Nav Three" component={Link} to="/nav-three" {...a11yProps(2)} /> </Tabs> <Routes> <Route path="/nav-one" element={<div>Nav One Content</div>} /> <Route path="/nav-two" element={<div>Nav Two Content</div>} /> <Route path="/nav-three" element={<div>Nav Three Content</div>} /> </Routes> </Router> ); } export default NavTabs;
Import the NavTabs.jsx component inside the App.jsx component:
// App.jsx import NavTabs from "./components/NavTabs"; const App = () => ( <div> <NavTabs /> </div> ); export default App;
Output
If you click on the “Nav Two” tab, the URL will change, and the content will be displayed based on that tab.
Icon Tabs
To enhance your visual navigation experience, you can use icons or icons combined with text in a navigation tab. Install @mui/icons-material library using the below command:
npm install @mui/icons-material
Create a new file called IconTabs.jsx inside the src folder and add the below code:
// IconTabs.jsx import React from "react"; import { Tabs, Tab } from "@mui/material"; import FavoriteIcon from "@mui/icons-material/Favorite"; import HomeIcon from "@mui/icons-material/Home"; import PersonIcon from "@mui/icons-material/Person"; import TabPanel from "./TabPanel"; function a11yProps(index) { return { id: `tab-${index}`, "aria-controls": `tabpanel-${index}`, }; } function IconTabs() { const [tabValue, setTabValue] = React.useState(0); const handleTabChange = (event, newValue) => { setTabValue(newValue); }; return ( <div> <Tabs value={tabValue} onChange={handleTabChange} aria-label="icon tabs example" > <Tab icon={<HomeIcon />} aria-label="home" {...a11yProps(0)} /> <Tab icon={<FavoriteIcon />} aria-label="favorite" {...a11yProps(1)} /> <Tab icon={<PersonIcon />} aria-label="person" {...a11yProps(2)} /> </Tabs> <TabPanel value={tabValue} index={0}> Home Content </TabPanel> <TabPanel value={tabValue} index={1}> Favorite Content </TabPanel> <TabPanel value={tabValue} index={2}> Person Content </TabPanel> </div> ); } export default IconTabs;
Import the IconTabs.jsx component inside the App.jsx component:
// IconTabs.jsx import IconTabs from "./components/IconTabs"; const App = () => ( <div> <IconTabs /> </div> ); export default App;
Output
That’s all!
Here is the complete Github Code.