Material-ui: ClickAwayListener triggers on Material Select (and more)

Created on 2 Jul 2018  路  7Comments  路  Source: mui-org/material-ui

This is best explained using code.

The following example is constructed by copy/pasting code form the docs and combining ClickAwayListener and Select.

When an option in Select is chosen the ClickAwayListener triggers the callback, despite Select being its descendant.

<ClickAwayListener onClickAway={this.handleClickAway}>
    <Paper className={classes.paper}>
        <Select
            multiple
            value={this.state.selected}
            onChange={this.handleChange}
            input={<Input id="select-multiple" />}
            MenuProps={MenuProps}>
            {names.map(name => (
                <MenuItem key={name} value={name}>
                    {name}
                </MenuItem>
            ))}
        </Select>
    </Paper>
</ClickAwayListener>

  • [x] This is a v1.x issue (v0.x is no longer maintained).
  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior


Select should normally close with the chosen value being the current in the Select and the click-away trigger shouldn't fire.

Current Behavior


When an option in Select is chosen the ClickAwayListener triggers the callback, despite Select being its descendant.

Note that this doesn't happen if select is in native mode with options instead of MenuItems. The same behaviour is exhibited in both multi- and regular Selects.

Steps to Reproduce (for bugs)

See codesandbox: https://codesandbox.io/s/3qq7l6478m, forked from the one in docs: https://codesandbox.io/s/6llvjywwq3

Context


I have a Select in a Drawer that contains a form. The Drawer has ClickAwayListener enveloping its content, including Select.

When a value is chosen in Select, the click-away trigger is executed (and it closes the Drawer in my app).

Your Environment

| Tech | Version |
|--------------|---------|
| Material-UI | v1.?.? |
| React | 16.4.1 |
| browser | Chrome |
| etc | |

ClickAwayListener discussion

Most helpful comment

Easy enough to work around this

Add an id or some other identifier to the MenuItem component thats falsley triggering the ClickAwayListener component.

On the ClickAwayListener.onClickAway event, check that the e.target doesn't match the pattern before triggering whatever action you're taking on the onClickAway event (such as closing the Popover)

All 7 comments

@dnutels The Select portals the options to the end of the body element. You can't use the ClickAwayListener this way. I see two alternatives:

  1. Use the native select implementation
  2. Change the select container to be within the drawer

@oliviertassinari So... custom Select or native select then? Alright.

custom Select

@dnutels There is a container property. We could also think of disabling the Portal behavior. I'm wondering how this would behave.

Yeah, I don't think that we can do anything at the ClickAwayListener component level, this component works with native DOM events, not the simulated ones by React.

I'm having the same kind of problem: click on a Select option triggers ClickAwayListener and closes my Collapse, even though Select is a descendant of ClickAwayListener (not a direct child though).

I saw the PR fixing the problem but I can't understand how it applies to Select component: I only see disablePortal prop in Modal and Popper components.

Easy enough to work around this

Add an id or some other identifier to the MenuItem component thats falsley triggering the ClickAwayListener component.

On the ClickAwayListener.onClickAway event, check that the e.target doesn't match the pattern before triggering whatever action you're taking on the onClickAway event (such as closing the Popover)

https://github.com/mui-org/material-ui/issues/13216#issuecomment-429527839
This works for me.
Also, if you are using TextField

 <TextField
        select
        label={"Name"}
        value={value}
        onChange={selectValue}
            SelectProps={{
                MenuProps: { disablePortal: true }
            }}
   >
        {[1, 2, 3].map((value, index) =>
              <MenuItem key={index} value={value}>
                      {value}
               </MenuItem>
         )}
 </TextField>

Note that #18586 has a proposed solution to a builtin solution to the problem, it's up for a pull request :).

Was this page helpful?
0 / 5 - 0 ratings