I'm struggling a bit about this code below describing the basic layout of a React / Material UI layout with a toolbar and a sidenavbar.
The burger button in the toolbar currently toggles the drawer only on small screens, I'm not sure how I can keep a consistent behaviour even when on bigger displays/screens?
import * as React from "react";
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import CssBaseline from "@mui/material/CssBaseline";
import Divider from "@mui/material/Divider";
import Drawer from "@mui/material/Drawer";
import IconButton from "@mui/material/IconButton";
import InboxIcon from "@mui/icons-material/MoveToInbox";
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 MailIcon from "@mui/icons-material/Mail";
import MenuIcon from "@mui/icons-material/Menu";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
const drawerWidth = 240;
interface Props {
/**
* Injected by the documentation to work in an iframe.
* Remove this when copying and pasting into your project.
*/
window?: () => Window;
}
export default function ResponsiveDrawer(props: Props) {
const { window } = props;
const [mobileOpen, setMobileOpen] = React.useState(false);
const [isClosing, setIsClosing] = React.useState(false);
const handleDrawerClose = () => {
setIsClosing(true);
setMobileOpen(false);
};
const handleDrawerTransitionEnd = () => {
setIsClosing(false);
};
const handleDrawerToggle = () => {
if (!isClosing) {
setMobileOpen(!mobileOpen);
}
};
const drawer = (
<div>
<Toolbar />
<Divider />
<List>
{["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => (
<ListItem key={text} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
<Divider />
<List>
{["All mail", "Trash", "Spam"].map((text, index) => (
<ListItem key={text} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
</div>
);
// Remove this const when copying and pasting into your project.
const container =
window !== undefined ? () => window().document.body : undefined;
return (
<Box sx={{ display: "flex" }}>
<CssBaseline />
<AppBar
position="fixed"
sx={{
zIndex: (theme) => theme.zIndex.drawer + 1,
}}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div">
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<Box
component="nav"
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
aria-label="mailbox folders"
>
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Drawer
container={container}
variant="temporary"
open={mobileOpen}
onTransitionEnd={handleDrawerTransitionEnd}
onClose={handleDrawerClose}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: "block", sm: "none" },
"& .MuiDrawer-paper": {
boxSizing: "border-box",
width: drawerWidth,
},
}}
>
{drawer}
</Drawer>
<Drawer
variant="permanent"
sx={{
display: { xs: "none", sm: "block" },
"& .MuiDrawer-paper": {
boxSizing: "border-box",
width: drawerWidth,
},
}}
open
>
{drawer}
</Drawer>
</Box>
<Box
component="main"
sx={{
flexGrow: 1,
p: 3,
width: { sm: `calc(100% - ${drawerWidth}px)` },
}}
>
<Toolbar />
<Typography>aaa</Typography>
<Typography>bbb</Typography>
</Box>
</Box>
);
}
Thanks to the answer given by @Simran Singh,
https://codesandbox.io/p/sandbox/cocky-napier-76v8pz
Here is the working code below:
import * as React from "react";
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import CssBaseline from "@mui/material/CssBaseline";
import Divider from "@mui/material/Divider";
import Drawer from "@mui/material/Drawer";
import IconButton from "@mui/material/IconButton";
import InboxIcon from "@mui/icons-material/MoveToInbox";
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 MailIcon from "@mui/icons-material/Mail";
import MenuIcon from "@mui/icons-material/Menu";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
const drawerWidth = 240;
interface Props {
/**
* Injected by the documentation to work in an iframe.
* Remove this when copying and pasting into your project.
*/
window?: () => Window;
}
export default function ResponsiveDrawer(props: Props) {
const { window } = props;
const [mobileOpen, setMobileOpen] = React.useState(false);
const [isClosing, setIsClosing] = React.useState(false);
const handleDrawerClose = () => {
setIsClosing(true);
setMobileOpen(false);
};
const handleDrawerTransitionEnd = () => {
setIsClosing(false);
};
const handleDrawerToggle = () => {
if (!isClosing) {
setMobileOpen(!mobileOpen);
}
};
const drawer = (
<div>
<Toolbar />
<Divider />
<List>
{["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => (
<ListItem key={text} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
<Divider />
<List>
{["All mail", "Trash", "Spam"].map((text, index) => (
<ListItem key={text} disablePadding>
<ListItemButton>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
</div>
);
// Remove this const when copying and pasting into your project.
const container =
window !== undefined ? () => window().document.body : undefined;
return (
<Box sx={{ display: "flex" }}>
<CssBaseline />
<AppBar
position="fixed"
sx={{
width: "100%",
zIndex: (theme) => theme.zIndex.drawer + 1,
}}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div">
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<Box
component="nav"
sx={{
width: mobileOpen ? { sm: drawerWidth } : 0,
flexShrink: 0,
transition: (theme) =>
theme.transitions.create(["width"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
}}
aria-label="mailbox folders"
>
<Drawer
container={container}
variant="temporary"
open={mobileOpen}
onTransitionEnd={handleDrawerTransitionEnd}
onClose={handleDrawerClose}
sx={{
display: { xs: "block", sm: "none" },
"& .MuiDrawer-paper": {
boxSizing: "border-box",
width: drawerWidth,
},
}}
slotProps={{
root: {
keepMounted: true, // Better open performance on mobile.
},
}}
>
{drawer}
</Drawer>
<Drawer
variant="persistent"
sx={{
display: { xs: "none", sm: "block" },
"& .MuiDrawer-paper": {
boxSizing: "border-box",
width: drawerWidth,
},
}}
open={mobileOpen}
>
{drawer}
</Drawer>
</Box>
<Box
component="main"
sx={{
flexGrow: 1,
p: 3,
width: mobileOpen ? { sm: `calc(100% - ${drawerWidth}px)` } : "100%",
transition: (theme) =>
theme.transitions.create(["width", "margin"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
}}
>
<Toolbar />
<Typography sx={{ marginBottom: 2 }}>bbb</Typography>
<Typography sx={{ marginBottom: 2 }}>aaa</Typography>
</Box>
</Box>
);
}
Your code has two Drawer components. The breakpoints in sx
prop show one Drawer
and hide another based on screen width.
//Drawe One, Show it on smaller screens only (xs)
<Drawer
variant="temporary"
sx={{
display: { xs: "block", sm: "none" }
}}
>
{drawer}
</Drawer>
//Drawer Two, Show it on wider screens only (sm)
<Drawer
variant="permanent"
sx={{
display: { xs: "none", sm: "block" }
}}
>
{drawer}
</Drawer>
🟢 What you're looking for is a variant="persistent"
Drawer. You can find an example here in the official MUI docs.