Creating a Material UI Dashboard
by iamvkr on
Material UI (MUI) is a popular React UI library that provides a set of pre-designed components following the Material Design guidelines. These components can be easily customized and are highly reusable, making MUI a great choice for building modern web applications. In this blog post, we’ll guide you through creating a responsive dashboard layout using MUI’s AppBar, Toolbar, and Drawer components
Table of contents
- Setting Up Your Project
- Basic Structure
- Result
- Explanation of the MUI Dashboard Code
- Login enabled Dashboard
Setting Up Your Project
Before we begin, ensure you have a React project set up and the necessary MUI dependencies installed. If you don’t have these, here’s how to create a new React project and install MUI:
npm install @mui/material @emotion/react @emotion/styled @mui/icons-material
Note: Make sure to have your react project setup
Basic Structure
Let’s start by creating the basic structure of our dashboard layout. We’ll use the AppBar for the top navigation, the Toolbar to hold elements within the AppBar, and the Drawer for the sidebar.
import React from 'react';
import {
AppBar, Box, CssBaseline, Divider, Drawer,
IconButton, List, ListItem, ListItemText, Toolbar,
Typography, useTheme, useMediaQuery, Paper,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
const drawerWidth = 240;
function Dashboard() {
const [mobileOpen, setMobileOpen] = React.useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
const drawer = (
<div>
<Toolbar></Toolbar>
<Divider />
<List>
{['Dashboard', 'Profile', 'Settings'].map((text) => (
<ListItem button key={text}>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</div>
);
return (
<Box sx={{ display: 'flex' }}>
<CssBaseline />
{/* App Bar */}
<AppBar
position="fixed"
sx={{
width: { md: `calc(100% - ${drawerWidth}px)`},
ml: { md: `${drawerWidth}px` },
}}
>
<Toolbar>
{isMobile && (
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
)}
<Typography variant="h6" noWrap component="div">
Dashboard
</Typography>
</Toolbar>
</AppBar>
{/* Sidebar */}
<Box
component="nav"
sx={{ width: { md: drawerWidth }, flexShrink: { md: 0 } }}
aria-label="sidebar folders"
>
{/* Temporary drawer for mobile */}
<Drawer
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{ keepMounted: true }} // Better open performance on mobile
sx={{
display: { xs: 'block', md: 'none' },
'& .MuiDrawer-paper': { width: drawerWidth },
}}
>
{drawer}
</Drawer>
{/* Permanent drawer for desktop */}
<Drawer
variant="permanent"
sx={{
display: { xs: 'none', md: 'block' },
'& .MuiDrawer-paper': { width: drawerWidth, boxSizing: 'border-box' },
}}
open
>
{drawer}
</Drawer>
</Box>
{/* Main Content */}
<Box
component="main"
sx={{
flexGrow: 1,
p: 3,
width: { md: `calc(100% - ${drawerWidth}px)` },
}}
>
<Toolbar />
<Typography paragraph>
Welcome to the dashboard. This section contains the main content.
</Typography>
</Box>
</Box>
);
}
export default Dashboard;
Result
Explanation of the MUI Dashboard Code
Here’s a breakdown of the provided React code for creating a responsive MUI dashboard:
-
useState(false)
for Mobile Drawer:const [mobileOpen, setMobileOpen] = React.useState(false);
Initializes a state variable
mobileOpen
tofalse
. This state controls the visibility of the temporary drawer (sidebar for mobile devices). -
useTheme()
Hook:const theme = useTheme();
Provides access to your application’s Material UI (MUI) theme object. This allows you to utilize theme-defined values, such as breakpoints for responsive design.
-
useMediaQuery()
for Responsiveness:const isMobile = useMediaQuery(theme.breakpoints.down('md'));
A hook that returns
true
if the current screen width is less than or equal to the “medium” (md
) breakpoint defined in your MUI theme, andfalse
otherwise. This helps in conditionally rendering UI elements based on screen size. -
drawer
Variable (JSX for Sidebar Content):const drawer = ( /** .... */ );
This variable holds the JSX structure for the sidebar’s content:
Toolbar
: An empty toolbar at the top of the drawer, often used for branding or additional controls.List
andListItem
: MUI components for creating a list of interactive items, used here for navigation links.
-
CssBaseline
:<CssBaseline />
Provides a basic reset of browser default styles, ensuring a consistent look and feel across different browsers.
-
<AppBar>
Component (Fixed Position):<AppBar position="fixed" sx={{ width: { md: `calc(100% - ${drawerWidth}px)` }, ml: { md: `${drawerWidth}px` }, }} > {/* ... Toolbar inside AppBar ... */} </AppBar>
Creates the top application bar that remains fixed at the top of the viewport during scrolling.
-
<Toolbar>
Inside<AppBar>
:<Toolbar> {isMobile && ( <IconButton color="inherit" aria-label="open drawer" edge="start" onClick={handleDrawerToggle} sx={{ mr: 2 }} > <MenuIcon /> </IconButton> )} <Typography variant="h6" noWrap component="div"> Dashboard </Typography> </Toolbar>
Holds the content of the AppBar:
- Conditional Rendering of Menu Icon (
isMobile && (...)
): TheIconButton
with theMenuIcon
is only displayed on mobile devices (isMobile
istrue
). onClick={handleDrawerToggle}
: When the menu icon is clicked, it triggers thehandleDrawerToggle
function to open the mobile drawer.Typography
: Displays the title of the dashboard.
- Conditional Rendering of Menu Icon (
-
Temporary
Drawer
(for Mobile):<Drawer variant="temporary" open={mobileOpen} onClose={handleDrawerToggle} ModalProps={{ keepMounted: true }} // Better open performance on mobile sx={{ display: { xs: 'block', md: 'none' }, '& .MuiDrawer-paper': { width: drawerWidth }, }} > {drawer} </Drawer>
A drawer that slides in as a modal on smaller screens.
variant="temporary"
: Indicates a modal-like drawer.open={mobileOpen}
: Controls its visibility based on themobileOpen
state.onClose={handleDrawerToggle}
: Called when the user tries to close the drawer (e.g., by clicking outside).ModalProps={{ keepMounted: true }}
: Optimizes performance on mobile devices by keeping the drawer’s content mounted in the DOM.sx
Styling:display: { xs: 'block', md: 'none' }
: Visible on extra-small screens and hidden on medium and larger screens.'& .MuiDrawer-paper': { width: drawerWidth }
: Sets the width of the drawer’s visible area.
{drawer}
: Renders the sidebar content defined earlier.
-
Permanent
Drawer
(for Desktop):<Drawer variant="permanent" sx={{ display: { xs: 'none', md: 'block' }, '& .MuiDrawer-paper': { width: drawerWidth, boxSizing: 'border-box' }, }} open > {drawer} </Drawer>
A drawer that is always visible on larger screens.
variant="permanent"
: Indicates a persistent sidebar.sx
Styling:display: { xs: 'none', md: 'block' }
: Hidden on extra-small screens and visible on medium and larger screens.'& .MuiDrawer-paper': { width: drawerWidth, boxSizing: 'border-box' }
: Sets the width and ensures thebox-sizing
includes padding and border in the width calculation.
open
: Set totrue
to keep it always open on desktop.{drawer}
: Renders the same sidebar content.
-
Main Content (
<Box component="main" ...>
):<Box component="main" sx={{ flexGrow: 1, p: 3, width: { md: `calc(100% - ${drawerWidth}px)` }, }} > <Toolbar /> <Typography paragraph> Welcome to the dashboard. This section contains the main content. </Typography> </Box>
Contains the primary content area of the dashboard.
component="main"
: Semantically marks this as the main content.flexGrow: 1
: Allows thisBox
to take up the remaining available space in the flex container.p: 3
: Applies padding around the content.width: { md: \
calc(100% - ${drawerWidth}px)` }`: On medium and larger screens, its width is adjusted to avoid overlapping with the permanent sidebar.<Toolbar />
: An empty toolbar. This is crucial to push the main content down below the fixedAppBar
, preventing it from being hidden.<Typography paragraph>
: Placeholder text for the actual dashboard content.
Login enabled Dashboard
We can also modify the code so that we can render the sidebar conditionally based on the application login state.
/** import statements */
const drawerWidth = 240;
function Dashboard() {
// ...
const [isLogin, setIsLogin] = React.useState(true);
// ...
const drawer = ({/* ... */});
return (
<Box sx={{ display: 'flex' }}>
<CssBaseline />
{/* App Bar */}
<AppBar
position="fixed"
sx={{
/** width based on login */
width: { md: isLogin ? `calc(100% - ${drawerWidth}px)`:"100%" },
ml: { md: `${drawerWidth}px` },
}}
>
<Toolbar>
{/* menu icon displayed based on login */}
{isMobile && isLogin && ({/** ... */})}
<Typography variant="h6" noWrap component="div">
Dashboard
</Typography>
</Toolbar>
</AppBar>
{/* Sidebar */}
{isLogin && <Box
// ...
>
{/* ... */}
</Box>}
{/* Main Content */}
<Box
// ...
>
<Toolbar />
<Typography paragraph>
Welcome to the dashboard. This section contains the main content.
</Typography>
</Box>
</Box>
);
}
export default Dashboard;
This code effectively creates a responsive dashboard layout using MUI components. It utilizes useMediaQuery
and conditional rendering of different Drawer
variants to provide an optimal user experience across various screen sizes. Remember to define the drawerWidth
constant in your component or theme for this code to function correctly.