Creating a responsive header for mobile and other devices is essential to accessing a wider audience. Users increasingly access websites from various devices with different screen sizes, so a responsive navbar ensures a seamless and user-friendly experience.
In this tutorial, we will learn how to create vertical tabs in React and Material UI. MUI provides a robust set of components and styling options that make the implementation of vertical tabs straightforward and highly customizable.
Creating a Basic Navbar
To get started, we need to install MUI dependencies in our React project:
npm install @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material
Let’s create a simple header with a logo on the left and navigation links on the right. The links will be defined in an array that we can loop through to populate the navbar, making it easy to add or remove items:
import React from "react";
import {
Stack,
Link,
Toolbar,
Typography,
Container,
AppBar,
} from "@mui/material";
const pages = [
{ name: "Products", id: "products" },
{ name: "Services", id: "services" },
{ name: "About", id: "about" },
{ name: "Testimonials", id: "testimonials" },
{ name: "Contact", id: "contact" },
];
const Header = () => {
return (
<AppBar>
<Container>
<Toolbar>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
width="100%"
>
<Typography variant="h6">My App</Typography>
<Stack direction="row" gap={3}>
{pages.map(page => (
<Link
key={page.id}
sx={{
color: { xs: "primary", sm: "white" },
}}
>
{page.name}
</Link>
))}
</Stack>
</Stack>
</Toolbar>
</Container>
</AppBar>
);
};
export default Header;
In the code above, we created a Header
component that renders the following components from MUI:
AppBar
: Creates an application bar that holds the navigation elements.Container
: Centers the content horizontally with padding on the sides.Toolbar
: Aligns its children horizontally, providing a flexible container within theAppBar
.Stack
: Arranges the logo and navigation links in a row, with the logo on the left and links on the right.
Responsive navbar with a drawer
There are multiple ways to create responsive layouts in MUI, but in this tutorial, we’ll use the sx
prop to handle the changes. For a more detailed understanding, you can refer to the tutorial on
Breakpoints and Responsive Design.
Let’s walk through how to make a responsive navbar using a drawer for mobile devices.
Simple Example to Show/Hide on Mobile
First, we’ll demonstrate how to show and hide elements based on the screen size using the sx
prop:
import { Box, Typography } from "@mui/material";
const ResponsiveExample = () => {
return (
<Box>
<Typography sx={{ display: { xs: "none", sm: "block" } }}>
Other Devices
</Typography>
<Typography sx={{ display: { xs: "block", sm: "none" } }}>
Mobile Device
</Typography>
</Box>
);
};
export default ResponsiveExample;
The breakpoint xs
applies to extra-small screens (mobile) up to sm
screens (small devices). Meanwhile, sm
applies to small devices and above because there is no breakpoint after sm,
so it will be applied to all other screens.
We can try to resize the window using the handle at the bottom right corner to see the text changing based on the screen size.
NavList Component
We’ll start by creating a NavList
component that will host the links and be responsible for updating the links’ direction, spacing, and other styling based on the breakpoint/device size:
const NavList = ({ ...props }) => {
return (
<Stack
overflow="auto"
direction={{ xs: "column", sm: "row" }}
gap={3}
ml={{ xs: 3, sm: 0 }}
mt={{ xs: 3, sm: 0 }}
width={{ xs: "150px", sm: "initial" }}
{...props}
>
{pages.map(page => (
<Link
key={page.id}
sx={{
color: { xs: "primary", sm: "white" },
}}
>
{page.name}
</Link>
))}
</Stack>
);
};
The Stack
component arranges the links in a column on mobile devices and a row on larger screens. We also set the margin and width based on the screen size to ensure proper spacing and alignment of the links.
Nav Component
The Nav
component will contain the menu button icon and Drawer
for mobile devices. The NavList
will be used within the Drawer
component for mobile and displayed directly for larger screens:
const Nav = () => {
const [open, setOpen] = useState(false);
const toggleDrawer = newOpen => () => {
setOpen(newOpen);
};
return (
<>
<Button
variant="text"
onClick={toggleDrawer(true)}
sx={{ color: "white", display: { xs: "flex", sm: "none" } }}
>
<MenuIcon />
</Button>
<Drawer
open={open}
onClose={toggleDrawer(false)}
anchor="right"
sx={{
display: { xs: "inherit", sm: "none" },
}}
>
<NavList />
</Drawer>
<NavList
sx={{
display: { xs: "none", sm: "inherit" },
}}
/>
</>
);
};
The Drawer
component creates a sliding menu that opens from the right side of the screen on mobile devices. The open
state and toggleDrawer
function are used to control the drawer’s visibility.
Complete Header Component
Now, we’ll put everything together by replacing the initial links we had in the header with the new Nav
component:
import React, { useState } from "react";
import {
Stack,
Link,
Toolbar,
Typography,
Container,
AppBar,
Button,
Drawer,
} from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
const pages = [
{ name: "Products", id: "products" },
{ name: "Services", id: "services" },
{ name: "About", id: "about" },
{ name: "Testimonials", id: "testimonials" },
{ name: "Contact", id: "contact" },
];
const NavList = ({ ...props }) => {
return (
<Stack
overflow="auto"
direction={{ xs: "column", sm: "row" }}
gap={3}
ml={{ xs: 3, sm: 0 }}
mt={{ xs: 3, sm: 0 }}
width={{ xs: "150px", sm: "initial" }}
{...props}
>
{pages.map(page => (
<Link
key={page.id}
sx={{
color: { xs: "primary", sm: "white" },
}}
>
{page.name}
</Link>
))}
</Stack>
);
};
const Nav = () => {
const [open, setOpen] = useState(false);
const toggleDrawer = newOpen => () => {
setOpen(newOpen);
};
return (
<>
<Button
variant="text"
onClick={toggleDrawer(true)}
sx={{ color: "white", display: { xs: "flex", sm: "none" } }}
>
<MenuIcon />
</Button>
<Drawer
open={open}
onClose={toggleDrawer(false)}
anchor="right"
sx={{
display: { xs: "inherit", sm: "none" },
}}
>
<NavList />
</Drawer>
<NavList
sx={{
display: { xs: "none", sm: "inherit" },
}}
/>
</>
);
};
const Header = () => {
return (
<AppBar>
<Container>
<Toolbar>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
width="100%"
>
<Typography variant="h6">My App</Typography>
<Nav />
</Stack>
</Toolbar>
</Container>
</AppBar>
);
};
export default Header;
When resizing the window in the above code example, the navbar changes its layout based on the screen size, and the navigation links are displayed in a drawer on mobile devices.
Mobile Menu Customization
MUI drawers allow us to change the position of the sliding menu using the anchor prop. Here’s an example of making the menu slide from the top:
<Drawer open={open} onClose={toggleDrawer(false)} anchor="top">
<NavList />
</Drawer>
The options for the anchor
prop are top
, bottom
, left
, and right
. For more details on the Drawer
component API, you can refer to the MUI Drawer documentation.
Customizing the Mobile Menu to Slide Full Screen
To make the menu appear friendlier on mobile devices, we can make it slide in as a full screen and tweak the drawer’s style. We’ll also add a handy “X” icon at the top right corner for users to easily close the menu, especially since clicking outside won’t work when the whole screen is covered.
import React, { useState } from "react";
import {
Stack,
Link,
Toolbar,
Typography,
Container,
AppBar,
Button,
Drawer,
Box,
} from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
import CloseIcon from "@mui/icons-material/Close";
const pages = [
{ name: "Products", id: "products" },
{ name: "Services", id: "services" },
{ name: "About", id: "about" },
{ name: "Testimonials", id: "testimonials" },
{ name: "Contact", id: "contact" },
];
const Nav = () => {
const [open, setOpen] = useState(false);
const toggleDrawer = newOpen => () => {
setOpen(newOpen);
};
return (
<>
<Button
variant="text"
onClick={toggleDrawer(true)}
sx={{ color: "white", display: { xs: "flex", sm: "none" } }}
>
<MenuIcon />
</Button>
<Drawer
open={open}
onClose={toggleDrawer(false)}
anchor="right"
sx={{
display: { xs: "inherit", sm: "none" },
"& .MuiDrawer-paper": {
height: "100%",
width: "100%",
},
}}
>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
p: 2,
}}
>
<Button onClick={toggleDrawer(false)}>
<CloseIcon />
</Button>
</Box>
<NavList />
</Drawer>
<NavList
sx={{
display: { xs: "none", sm: "inherit" },
}}
/>
</>
);
};
const NavList = ({ ...props }) => {
return (
<Stack
overflow="auto"
direction={{ xs: "column", sm: "row" }}
gap={3}
width={{ xs: "100%", sm: "initial" }}
textAlign={{ xs: "center", sm: "initial" }}
fontSize={{ xs: "22px", sm: "initial" }}
{...props}
>
{pages.map(page => (
<Link
key={page.id}
sx={{
color: { xs: "primary", sm: "white" },
textDecoration: "none",
}}
>
{page.name}
</Link>
))}
</Stack>
);
};
const Header = () => {
return (
<AppBar>
<Container>
<Toolbar>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
width="100%"
>
<Typography variant="h6">My App</Typography>
<Nav />
</Stack>
</Toolbar>
</Container>
</AppBar>
);
};
export default Header;
In the code above, we added a CloseIcon
to the drawer and customized its styling to cover the entire screen using the .MuiDrawer-paper
class. The NavList
component was also updated to adjust the text alignment, font size, and width based on the screen size.
Summary
In this tutorial, we created a responsive navbar using React and Material UI (MUI). Initially, we designed a basic navbar with a logo and navigation links. Then, we made the navbar responsive and added a drawer for better mobile experience. The result is a dynamic and user-friendly navbar for desktop and mobile devices.