Skip to main content Link Menu Expand (external link) Left Arrow Right Arrow Document Search Copy Copied

Vertical Tabs

The vertical tabs we created for the “Settings” page do not scale properly on mobile devices. We will modify the VerticalTabs component to use a small drawer for switching tabs on the “Settings” page when viewed on a small screen.

Limit Current Configuration to Medium (or Larger) Displays

We will start by limiting the current tabs setup to medium and large display using breakpoints.

Open the components/TabPanel/VerticalTabs.tsx file and replace the display: 'flex' line inside the Tabs component with display: {xs: 'none', md: 'flex'}.

Add Drawer

Start by adding the following import statements to VerticalTabs.tsx:

import Drawer from '@mui/material/Drawer';  
import List from '@mui/material/List';  
import ListItem from '@mui/material/ListItem';  
import ListItemButton from '@mui/material/ListItemButton';  
import ListItemIcon from '@mui/material/ListItemIcon';  
import ListItemText from '@mui/material/ListItemText';  
import FormatListBulletedOutlinedIcon from '@mui/icons-material/FormatListBulletedOutlined';  
import IconButton from "@mui/material/IconButton";

Next, add the following lines of code before the return statement:


// function that handles changing tabs in the tabs drawer
const handleChangeDrawer = (e: React.MouseEvent<HTMLDivElement>, newValue: number) => {
	setValue(newValue);
}

// declaring a state variable that determines if the tabs drawer is open and initializing it to false
const [state, setState] = React.useState(false);

// function used to open and close the tabs drawer
const toggleDrawer =
	(open: boolean) =>
		(event: React.KeyboardEvent | React.MouseEvent) => {
			if (
				event.type === 'keydown' &&
				((event as React.KeyboardEvent).key === 'Tab' ||
					(event as React.KeyboardEvent).key === 'Shift')
			) {
				return;
			}
			setState(open);
		};

// function used to render the items inside the tabs drawer
const list = () => (
	<Box
		sx={{ width:  250 }}
		role="presentation"
		onClick={toggleDrawer(false)}
		onKeyDown={toggleDrawer(false)}
>
		<List>
			{tabs.map((text, index) => (
				<ListItem key={text} disablePadding>
					<ListItemButton selected= {value === index} onClick={(e) => handleChangeDrawer(e, index)}>
						<ListItemIcon>
							{icons[index]}
						</ListItemIcon>
						<ListItemText primary={text} />
					</ListItemButton>
				</ListItem>
			))}
		</List>
	</Box>
);

The toggleDrawer function handles opening and closing the drawer using the state constant. The list function renders the components inside the drawer. Akin to the Tabs component, the drawer contains four tabs with appropriate iconography. The selected= {value === index} line in the ListItemButton component is used to highlight the tab that the user currently has open by comparing the value prop of the TabPanel component to the index of the tab.

We will now add the UI elements that should only be visible on smaller screens. We will add an IconButton to open and close the Drawer component.

Add the following lines of code right after the Tabs closing tag inside the return statement:


{/* adding an icon button to open/close the drawer on mobile devices */}
<Box sx={{paddingTop: '19px'}}>
	<IconButton title="Settings Drawer" aria-label="settings-menu" onClick={toggleDrawer(true)} sx={{ display: {xs: 'inline', md: 'none'}, height:'40px'}}> <FormatListBulletedOutlinedIcon /> </IconButton>
</Box>
{/* rendering the Drawer component */}
<Drawer
	anchor={"left"}
	open={state}
	onClose={toggleDrawer(false)}
	sx={{
		'& .MuiDrawer-root': {
			position: 'absolute'
		},
		'& .MuiPaper-root': {
			position: 'absolute'
		},
		minWidth: 100,
		width: "20%",
		position: "absolute",
		top: '230px',
		left: '2%',
		height: '50%',
		display: {xs: 'flex', md: 'none'}
	}}                        
>
	{list() /* calling list() to render the content of the tabs drawer */}
</Drawer>

We will also add a title to each panel that is only visible on small screens since the tab names are no longer visible when the user is on each tab.

Modify each TabPanel component by adding a Typography component to it and only displaying it on small screens using breakpoints:


<TabPanel value={value} index={0}>
	{/* adding a Typography component with the title of the active tab (only visible on small screens) */}
	<Typography
		sx={{display: {xs: 'flex', md: 'none'}, justifyContent: 'left', paddingLeft: '10px'}}
		variant="h3"
		gutterBottom
>
		Notifications
	</Typography>
	<FormControl sx={{m: 1, minWidth: 300}}>
		<InputLabel id="demo-simple-select-label">
			Demo Dropdown Menu
		</InputLabel>
		<Select
			labelId="demo-simple-select-label"
			id="demo-simple-select"
			label="Demo Dropdown Menu"
>
			<MenuItem value={1}>Option 1</MenuItem>
			<MenuItem value={2}>Option 2</MenuItem>
			<MenuItem value={3}>Option 3</MenuItem>
		</Select>
	</FormControl>
</TabPanel>
<TabPanel value={value} index={1}>
	<Typography
		sx={{display: {xs: 'flex', md: 'none'}, justifyContent: 'left', paddingLeft: '10px'}}
		variant="h3"
		gutterBottom
>
		Privacy
	</Typography>
	Placeholder 2
</TabPanel>
<TabPanel value={value} index={2}>
	<Typography
		sx={{display: {xs: 'flex', md: 'none'}, justifyContent: 'left', paddingLeft: '10px'}}
		variant="h3"
		gutterBottom
>
		Accessibility
	</Typography>
	Placeholder 3
</TabPanel>
<TabPanel value={value} index={3}>
	<Typography
		sx={{display: {xs: 'flex', md: 'none'}, justifyContent: 'left', paddingLeft: '10px'}}
		variant="h3"
		gutterBottom
>
		Account
	</Typography>
	Placeholder 4
</TabPanel>

Notice that we used a custom Typography variant that we defined earlier in theme.ts for these titles.

Save the file and go back to your browser. Try shrinking the window and notice how the tabs are replaced with a drawer.

tab-drawer-closed

We also retain an active indicator to inform the user of the current tab that they are on.

tab-drawer-open