Material UI persistent drawer - content body not resizing

Viewed 298

I have an application with a persistent drawer. The drawer contains linked routes to various other components.

In general the drawer itself works fine, but the loaded components are not resizing, when the drawer opens or closes.

In the samples on the mui doc pages this functionality in implemented in the styled main component. Means the content is in the same component as the drawer. This is different in my app, where i have an index file with the routes, a navigationbar file with the drawer and the other components with their respective files.

So, how do i implement this resizing with loaded components?

index.tsx

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import NavigationBar from "./ADBPM-Components/NavigationBar";
import Login from "./login";
import PrivateRoute from "./login/PrivateRoute";
import Authenticator from "./login/auth";
import NotFound from "./notFound";
import WelcomeScreen from "./welcomeScreen";
import Test from "./test";

//Check if already authenticated
Authenticator.refreshState(() => {
  refreshPage();
});

export const refreshPage = () => {
  ReactDOM.render(    
    <Router>
      <div>
        <PrivateRoute noRedirect path="/" component={NavigationBar} />
        <Switch>
          <PrivateRoute exact path="/" component={WelcomeScreen} />
          <PrivateRoute path="/test" component={Test} />
          <PrivateRoute path="/changepass" component={ChangePassword} />
          <PrivateRoute path="/createuser" component={CreateUser} />

          <Route path="/login" component={Login} />
          <Route path="/signup" component={CreateUser} />

          <PrivateRoute path="/" component={NotFound} />
        </Switch>
      </div>
    </Router>,
    document.getElementById("app")
  );
};

NavigationBar.tsx

import * as React from "react";
import { withRouter } from "react-router";
import { Link } from "react-router-dom";


import { Divider } from "@material-ui/core";
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import MenuIcon from '@mui/icons-material/Menu';
import Drawer from '@mui/material/Drawer';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar';
import { styled, useTheme } from '@mui/material/styles';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import ListItemText from '@mui/material/ListItemText';
import CssBaseline from '@mui/material/CssBaseline';
import PeopleIcon from '@mui/icons-material/People';
import QueryStatsIcon from '@mui/icons-material/QueryStats';
import BuildIcon from '@mui/icons-material/Build';
import RequestPageIcon from '@mui/icons-material/RequestPage';
import LogoutOutlinedIcon from '@mui/icons-material/LogoutOutlined';
import PasswordIcon from '@mui/icons-material/Password';
import SupervisedUserCircleIcon from '@mui/icons-material/SupervisedUserCircle';
import TableViewIcon from '@mui/icons-material/TableView';

import Authenticator from "../login/auth";
import * as pack from "../../package.json";
import { Fragment } from "react";

const drawerWidth = 240;

interface AppBarProps extends MuiAppBarProps {
  open?: boolean;
}

const AppBar = styled(MuiAppBar, {
  shouldForwardProp: (prop) => prop !== 'open',
})<AppBarProps>(({ theme, open }) => ({
  transition: theme.transitions.create(['margin', 'width'], {
    easing: theme.transitions.easing.sharp,
    duration: theme.transitions.duration.leavingScreen,
  }),
  ...(open && {
    width: `calc(100% - ${drawerWidth}px)`,
    marginLeft: `${drawerWidth}px`,
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
  }),
}));

const DrawerHeader = styled('div')(({ theme }) => ({
  display: 'flex',
  alignItems: 'center',
  padding: theme.spacing(0, 1),
  // necessary for content to be below app bar
  ...theme.mixins.toolbar,
  justifyContent: 'flex-end',
}));


function NavigationBar() {

  const theme = useTheme();
  const [open, setOpen] = React.useState(false);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <Fragment>
      <Box sx={{ display: 'flex' }}>
        <CssBaseline />
        <AppBar position="fixed" open={open}>
          <Toolbar>
            <IconButton
              color="inherit"
              aria-label="open drawer"
              onClick={handleDrawerOpen}
              edge="start"
              sx={{ mr: 2, ...(open && { display: 'none' }) }}
            >
              <MenuIcon />
            </IconButton>
            <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
              ADBPM ({pack.version})
            </Typography>
            <Typography variant="h6" component="div" sx={{ flexGrow: 1 }} align="right">
              {` Logged in as ${Authenticator.user}`}
            </Typography>
          </Toolbar>
        </AppBar>
        <Drawer
          sx={{
            width: drawerWidth,
            flexShrink: 0,
            '& .MuiDrawer-paper': {
              width: drawerWidth,
              boxSizing: 'border-box',
            },
          }}
          variant="persistent"
          anchor="left"
          open={open}
        >
          <DrawerHeader>
            <IconButton onClick={handleDrawerClose}>
              {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
            </IconButton>
          </DrawerHeader>
          <Divider />
          <List>
            <ListItem button key='Test' component={Link} to="/test">
              <ListItemIcon>
                <QueryStatsIcon />
              </ListItemIcon>
              <ListItemText primary='Test' />
            </ListItem>
          </List>
          <Divider />
          <List>
            <ListItem button key='Change My Password' component={Link} to="/changepass">
              <ListItemIcon>
                <PasswordIcon />
              </ListItemIcon>
              <ListItemText primary='Change My Password' />
            </ListItem>
            <ListItem button key='LogOut' onClick={() => {Authenticator.logout();}}>
              <ListItemIcon>
                <LogoutOutlinedIcon />
              </ListItemIcon>
              <ListItemText primary='LogOut' />
            </ListItem>
          </List>
        </Drawer>
      </Box>
      <Toolbar />
    </Fragment>
  );
}

export default withRouter(NavigationBar);

test.tsx

import React from "react";
import { RouteComponentProps } from "react-router";

class Test extends React.Component{
  constructor(props: RouteComponentProps){
    super(props);
  }

render(): JSX.Element {
  return (
    <div>
      <h4>
        It is only a Test. 
      </h4>
    </div>
  );
}
}

export default Test;
1 Answers

I had a similar problem.

I ended up wrapping the router in a Box element with the styling in the Persistent Drawer demo.

https://codesandbox.io/s/2g979p?file=/demo.js:966-1552

const Main = styled(Box, { shouldForwardProp: (prop) => prop !== 'open' })(
  ({ theme, open }) => ({
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
    marginLeft: `-${drawerWidth}px`,
    ...(open && {
      transition: theme.transitions.create('margin', {
        easing: theme.transitions.easing.easeOut,
        duration: theme.transitions.duration.enteringScreen,
      }),
      marginLeft: 0,
    }),
  }),
);
Related