MUI - Responsive Drawer MUI - Responsive Drawer reactjs reactjs

MUI - Responsive Drawer


For those who're working with material-UI V1 and higher, using breakpoints is the best way to make responsive layouts.

Breakpoints:

  • xs, extra-small: 0px or larger
  • sm, small: 600px or larger
  • md, medium: 960px or larger
  • lg, large: 1280px or larger
  • xl, xlarge: 1920px or larger

So, for changing React rendering tree you should pass different breakpoint parameter value into breakpoints.up() in the JSS:

navIconHide: {    [theme.breakpoints.up('md')]: {      display: 'none',    },  },  toolbar: theme.mixins.toolbar,  drawerPaper: {    width: drawerWidth,    [theme.breakpoints.up('md')]: {      position: 'relative',    },  },

The whole Drawer source code follows below.

import React from 'react';import PropTypes from 'prop-types';import { withStyles } from '@material-ui/core/styles';import Drawer from '@material-ui/core/Drawer';import AppBar from '@material-ui/core/AppBar';import Toolbar from '@material-ui/core/Toolbar';import List from '@material-ui/core/List';import Typography from '@material-ui/core/Typography';import IconButton from '@material-ui/core/IconButton';import Hidden from '@material-ui/core/Hidden';import Divider from '@material-ui/core/Divider';import MenuIcon from '@material-ui/icons/Menu';import { mailFolderListItems, otherMailFolderListItems } from './tileData';const drawerWidth = 240;const styles = theme => ({  root: {    flexGrow: 1,    height: 430,    zIndex: 1,    overflow: 'hidden',    position: 'relative',    display: 'flex',    width: '100%',  },  appBar: {    position: 'absolute',    marginLeft: drawerWidth,    [theme.breakpoints.up('md')]: {      width: `calc(100% - ${drawerWidth}px)`,    },  },  navIconHide: {    [theme.breakpoints.up('md')]: {      display: 'none',    },  },  toolbar: theme.mixins.toolbar,  drawerPaper: {    width: drawerWidth,    [theme.breakpoints.up('md')]: {      position: 'relative',    },  },  content: {    flexGrow: 1,    backgroundColor: theme.palette.background.default,    padding: theme.spacing.unit * 3,  },});class ResponsiveDrawer extends React.Component {  state = {    mobileOpen: false,  };  handleDrawerToggle = () => {    this.setState(state => ({ mobileOpen: !state.mobileOpen }));  };  render() {    const { classes, theme } = this.props;    const drawer = (      <div>        <div className={classes.toolbar} />        <Divider />        <List>{mailFolderListItems}</List>        <Divider />        <List>{otherMailFolderListItems}</List>      </div>    );    return (      <div className={classes.root}>        <AppBar className={classes.appBar}>          <Toolbar>            <IconButton              color="inherit"              aria-label="Open drawer"              onClick={this.handleDrawerToggle}              className={classes.navIconHide}            >              <MenuIcon />            </IconButton>            <Typography variant="title" color="inherit" noWrap>              Responsive drawer            </Typography>          </Toolbar>        </AppBar>        <Hidden mdUp>          <Drawer            variant="temporary"            anchor={theme.direction === 'rtl' ? 'right' : 'left'}            open={this.state.mobileOpen}            onClose={this.handleDrawerToggle}            classes={{              paper: classes.drawerPaper,            }}            ModalProps={{              keepMounted: true, // Better open performance on mobile.            }}          >            {drawer}          </Drawer>        </Hidden>        <Hidden smDown implementation="css">          <Drawer            variant="permanent"            open            classes={{              paper: classes.drawerPaper,            }}          >            {drawer}          </Drawer>        </Hidden>        <main className={classes.content}>          <div className={classes.toolbar} />          <Typography noWrap>{'You think water moves fast? You should see ice.'}</Typography>        </main>      </div>    );  }}ResponsiveDrawer.propTypes = {  classes: PropTypes.object.isRequired,  theme: PropTypes.object.isRequired,};export default withStyles(styles, { withTheme: true })(ResponsiveDrawer);


You could listen for screen size changes in componentWillMount like this, I'm sure there are better methods but this works.

toggleOpenDrawer = () => {    if (!this.state.mobile) {        return;    }    this.setState({        open: !this.state.open    })}setSmall = () => {    this.setState({open: false, docked: false, mobile: true})}setLarge = () => {    this.setState({open: true, docked: true, mobile: false})}componentWillMount() {  const mediaQuery = window.matchMedia('(min-width: 768px)');  if (mediaQuery.matches) {    this.setLarge()  } else {    this.setSmall()  }  mediaQuery.addListener((mq) => {    if (mq.matches) {      this.setLarge()    } else {      this.setSmall()    }  });}


In MUI v5, you can display 2 Drawers in different screen sizes. The permanent Drawer is always visible in the larger screen. In small screen, you can remove it easily using responsive values in sx prop:

<Drawer  variant="permanent"  open  sx={{ display: { xs: 'none', sm: 'block' } }}>

And show a temporary Drawer that can be opened or closed. The temporary one doesn't affect the layout since it appears on top which is suitable in mobile view.

<Drawer  variant="temporary"  open={mobileOpen}  onClose={handleDrawerToggle}  sx={{ display: { xs: 'block', sm: 'none' } }}>

Live Demo

Codesandbox Demo

Reference