Close Persistent MUI Drawer on clicking outside

Viewed 24136

I am trying to use Drawer component in MUI React. I want that state inside the Drawer component should not lost on closing of Drawer component, hence I'm passing variant="persistent" in Drawer component.

Now, the problem is that the Persistent Drawer does not provide backdrop functionality by default unlike temporary drawers hence I'm unable to close it on outside click. I tried {{ModalProps={{ onBackdropClick: this.toggleDrawer }} }} also but still it is not working.

Is there any workaround for this?

MUI Version: 1.0.0

CodeSandbox link

8 Answers

For the sake of searchers landing on this question. If you are having trouble with ClickAwayListener and are not using variant='persistent'. Try this instead: Providing a toggle function to ModalProps onBackdropClick

<Drawer
  open={drawerIsOpen}
  ModalProps={{ onBackdropClick: this.toggleDrawer }}
>
  <MenuItem>drawer item 1</MenuItem>
</Drawer>

UPDATE July 2021:

I recently updated material-ui/core to version 4.12.1 and noticed that onBackdropClick is being deprecated. Instead they have added native support for this functionality, the onClose function will be called automatically when clicking outside the drawer, and it now gives a reason for why it was called:

Signature: function(event: object, reason: string) => void

event: The event source of the callback.

reason: Can be: "escapeKeyDown", "backdropClick"

See example here: https://material-ui.com/api/modal/ scroll down to onBackDropClicked - it works the same for the drawer as it does for the

Do this instead:

<Drawer
  open={drawerIsOpen}
  onClose={{ (ev, reason) => this.setState({ drawerIsOpen: false }) }}
>
  <MenuItem>drawer item 1</MenuItem>
</Drawer>

You can use the ClickAwayListener component for this.
https://material-ui.com/api/click-away-listener/

import ClickAwayListener from '@material-ui/core/ClickAwayListener';

const drawer = (
      <ClickAwayListener onClickAway={this.handleDrawerClose}>
        <Drawer
          variant="persistent"
          anchor={anchor}
          open={open}
          classes={{
            paper: classes.drawerPaper
          }}
        >
          <div className={classes.drawerHeader}>
            <IconButton onClick={this.handleDrawerClose}>
              {theme.direction === "rtl" ? (
                <ChevronRightIcon />
              ) : (
                <ChevronLeftIcon />
              )}
            </IconButton>
          </div>
          <Divider />
          <List>a asdasd</List>
          <Divider />
          <List>asdasd</List>
        </Drawer>
      </ClickAwayListener>
    );

https://codesandbox.io/s/072ny1rjw

I spend some time training to fix this, but I found a really a useful solution and is to change the variant to Temporary and use de onEscapeKeyDown and the onBackdropClick as follow:

  <Drawer
    variant="temporary"
    onEscapeKeyDown={handleDrawerClose}
    onBackdropClick={handleDrawerClose}
    open={open}
    ...rest of your code...

You can implement this yourself by adding a div in your appFrame which has an onClick that closes the drawer like this:

<div className={classes.appFrame}>
{this.state.open ? 
    <div style={{ position: "fixed", zIndex: 1, left: 0, right: 0, top: 0, bottom: 0 }} 
        onClick={() => this.handleDrawerClose()} /> 
    : null
}
// rest of your code

Working solution in MUI v5:

Persistent Drawer

Use ClickAwayListener to know when the user clicks outside the Drawer. You also need to set mouseEvent="onMouseDown", otherwise the onClickAway callback is fired after the user clicks the open button and make the Drawer close immediately before it can be opened.

<ClickAwayListener
  mouseEvent="onMouseDown"
  touchEvent="onTouchStart"
  open={open}
  onClickAway={() => open && setOpen(false)}
>
  <Drawer variant="persistent" {...props} />
</ClickAwayListener>

Temporary Drawer

<Drawer
  variant="temporary"
  open={open}
  onClose={(_, reason) =>
    reason === 'backdropClick' && setOpen(false)
  }
>

Live Demo

Codesandbox Demo

I am not sure if it works with 1.0.0 version but this approach works for me noting that i am using the drawer from "material-ui/core @4.10"

<Drawer ... open={this.state.open} onClose={() => this.handleDrawerClose()}>
....
</Drawer>

Recently found out about this neat useOnClickOutside hook => CodeSandBox and replaced all my with it. Much more elegant than adding an element to the dom and really easy to use with Mui now that you can pass a ref prop to any Material-ui component.

You can use in Drawer's open attribute a useState and set to false in the onClose property:

onClose={() => setOpen(false)}

in this example, the useState name is ** open ** and ** setOpen **

Related