I have the below display sidebar Switch that shows up within a Popper. So, Ideally, if you click elsewhere (outside of the Popper element), Popper should disappear. If you click inside Popper element, it should not go anywhere. When I click on the Switch or Display Sidebar text, that Popper goes away. I wrapped the Popper with <div>
it didn't help either.
Popper https://material-ui.com/api/popper/
Switch https://material-ui.com/api/switch/
ClickAwayListener https://material-ui.com/utils/click-away-listener/
Below is the Popper Code
<ClickAwayListener onClickAway={this.handleClickAway}>
<div>
<Popper className={classes.popper} id={id} open={open} placement="bottom-end" anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<Paper className={classes.SliderBox}>
<Switch
checked={this.state.checkedB}
onChange={this.handleChange('checkedB')}
value="checkedB"
color="primary"
onClick={handleDrawer}
className={classNames(classes.menuButton, sidebar && classes.hide)}
/>
Display Sidebar
</Paper>
</Fade>
)}
</Popper>
</div>
</ClickAwayListener>
I have the sample here (though I couldn't get it work I don't know why it gives error on clickaway) https://codesandbox.io/s/8pkm3x1902
By default, Popper
leverages a portal (https://github.com/mui-org/material-ui/blob/v4.11.0/packages/material-ui/src/Popper/Popper.js#L202) which renders its content in a separate part of the DOM (as a direct child of the <body>
element) from where the Popper
element is. This means that you have the ClickAwayListener
around an empty <div>
, so a click anywhere (including within the Popper content) will be considered to be outside of that empty <div>
.
Moving the ClickAwayListener
directly around the Fade
(rather than around the Popper
) ensures that it is surrounding the actual content rendered by the Popper
.
Here's a working example based on your sandbox:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import Popper from "@material-ui/core/Popper";
import Fade from "@material-ui/core/Fade";
import Paper from "@material-ui/core/Paper";
import Switch from "@material-ui/core/Switch";
import Avatar from "@material-ui/core/Avatar";
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
class App extends Component {
state = {
anchorEl: null,
open: false,
checkedB: true
};
handleClick = (event) => {
const { currentTarget } = event;
this.setState((state) => ({
anchorEl: currentTarget,
open: !state.open
}));
};
handleChange = (name) => (event) => {
this.setState({
[name]: event.target.checked
});
};
handleClickAway = () => {
this.setState({
open: false
});
};
render() {
const { anchorEl, open } = this.state;
const { handleDrawer } = this.props;
const id = open ? "simple-popper" : null;
return (
<div className="App">
asdsadsa
<Avatar
alt="Test"
src="https://www.nretnil.com/avatar/LawrenceEzekielAmos.png"
style={{ margin: "0 10px" }}
onClick={this.handleClick}
/>
<div>
<Popper
id={id}
open={open}
placement="bottom-end"
anchorEl={anchorEl}
transition
>
{({ TransitionProps }) => (
<ClickAwayListener onClickAway={this.handleClickAway}>
<Fade {...TransitionProps} timeout={350}>
<Paper //className={classes.SliderBox}
>
<Switch
checked={this.state.checkedB}
onChange={this.handleChange("checkedB")}
value="checkedB"
color="primary"
onClick={handleDrawer}
/>
Display Sidebar
</Paper>
</Fade>
</ClickAwayListener>
)}
</Popper>
</div>
</div>
);
}
}
export default App;
ReactDOM.render(<App />, document.getElementById("root"));
In v4 the ClickAwayListener
supports recognizing that elements are within its React element tree even when they are rendered within a portal (the original question was for v3), but it is still more reliable to put the ClickAwayListener
inside the Popper
rather than outside to avoid the ClickAwayListener
firing on the click to open the Popper
which then makes it look like the Popper
isn't working since it immediately closes (example: https://codesandbox.io/s/popper-clickawaylistener-forked-x4j0l?file=/src/index.js).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With