The Ultimate MUI Click Away Listener Tutorial

MUI has a ClickAwayListener component for controlling user interaction with components. If you want to force interaction with a component, or create some UI behavior when a user clicks away, use the click away listener.

In this tutorial we will create a form that renders on Button click. If the user tries to close the form without pressing the submit button, they get a warning Toast.

MUI ClickAwayListener Tutorial
MUI ClickAwayListener Tutorial

The tutorial shows full example React code. We will also discuss solutions when the click away listener is not working.

How to Use the MUI ClickAwayListener

The MUI ClickAwayListener requires very little code. Choose the component that you want to detect clicks outside of, and wrap it in the ClickAwayListener. Here’s a simple example:

<ClickAwayListener onClickAway={handleClickAway}>
  <div>Testing...</div>
</ClickAwayListener>

It seems odd to think of a click away listener as a component, but that makes it easy to use from a DOM perspective. Interestingly, the “component” doesn’t render anything in the DOM.

Below is the code for this tutorial. First, we only render the form after the Button is clicked. The form is wrapped with ClickAwayListener.

Next, we create state variables for controlling when the form and the Snackbar alert are open. Finally, in the ClickAwayListener onClickAway handler, set the snackbarOpen value to true on click away.

That’s all it takes to create a basic click away listener in MUI.

import * as React from "react";
import {
  Alert,
  Button,
  ClickAwayListener,
  FormGroup,
  Snackbar,
  TextField,
} from "@mui/material";

export default function ClickAwayListenerForm() {
  const [formOpen, setFormOpen] = React.useState(false);
  const [snackbarOpen, setSnackbarOpen] = React.useState(false);
  
  const handleClickAway = () => setSnackbarOpen(true);
  return (
    <>
    
    <div style={{ width: "20vw", height: "20vh", display: 'flex', justifyContent: 'left', alignItems: 'top', flexDirection: 'column' }}>
      <Button onClick={()=>{console.log('clicked'); setFormOpen(true)}} sx={{mb:2}}>Open</Button>
      {formOpen ?
      <ClickAwayListener onClickAway={handleClickAway}>
        <form action="/somewhere.html">
          <FormGroup sx={{ padding: 2, borderRadius: 2, border: '1px solid', borderColor: 'primary.main' }}>
            <TextField sx={{ paddingBottom: 2 }} name="name" variant="outlined" placeholder="Enter Name..." />
            <Button onClick={() => setFormOpen(false)} variant="outlined">Submit</Button>
          </FormGroup>
        </form>
        </ClickAwayListener>
        : null}
    </div>
    <Snackbar
        open={snackbarOpen}
        autoHideDuration={3000}
        onClose={() => setSnackbarOpen(false)}
      >
        <Alert severity="error" sx={{ width: "100%" }}>
          You must submit the form!
        </Alert>
      </Snackbar>
    </>
  );
}

The ClickAwayListener has a few props not shown above, but they simply add more precision to the click listener (i.e. only fire on mouse up).

What to Do When the MUI ClickAwayListener is Not Working

If the click away listener is not working properly, check what component you wrapped. For example, any component that uses a Popper, such as the Select or Autocomplete components, render the Popper outside of the ‘expected’ DOM hierarchy (read about React Portal to learn more). It is not a child of the Autocomplete in the DOM.

What this means is if you wrap the Autocomplete with ClickAwayListener, then click the Popper, the onClickAway will fire. What you need to do is pass a custom popper with ClickAwayListener to the componentsProps.popper prop.

Related Links

Here are useful related posts:

MUI ClickAwayListener API

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.