Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ClickAwayListener] Triggers on Select (and more) #12034

Closed
2 tasks done
dnutels opened this issue Jul 2, 2018 · 15 comments
Closed
2 tasks done

[ClickAwayListener] Triggers on Select (and more) #12034

dnutels opened this issue Jul 2, 2018 · 15 comments
Assignees
Labels
bug 🐛 Something doesn't work component: ClickAwayListener The React component component: select This is the name of the generic UI component, not the React module!

Comments

@dnutels
Copy link

dnutels commented Jul 2, 2018

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>
  • This is a v1.x issue (v0.x is no longer maintained).
  • 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
@oliviertassinari
Copy link
Member

@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

@dnutels
Copy link
Author

dnutels commented Jul 3, 2018

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

@oliviertassinari
Copy link
Member

oliviertassinari commented Jul 3, 2018

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.

@oliviertassinari oliviertassinari added the component: modal This is the name of the generic UI component, not the React module! label Jul 3, 2018
@oliviertassinari oliviertassinari self-assigned this Jul 6, 2018
@pleopardi
Copy link

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.

@butchmarshall
Copy link

butchmarshall commented Jul 23, 2019

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)

@Joycechocho
Copy link

Joycechocho commented Mar 5, 2020

#13216 (comment)
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>

@oliviertassinari
Copy link
Member

oliviertassinari commented Mar 8, 2020

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

@oliviertassinari oliviertassinari added component: ClickAwayListener The React component and removed component: modal This is the name of the generic UI component, not the React module! labels Apr 4, 2020
@NPatel10
Copy link

Setting mouseEvent property to 'onMouseUp' in ClickAwayListener worked for me.

@oliviertassinari oliviertassinari added bug 🐛 Something doesn't work component: select This is the name of the generic UI component, not the React module! and removed discussion labels Apr 28, 2021
@oliviertassinari oliviertassinari changed the title ClickAwayListener triggers on Material Select (and more) [ClickAwayListener] Triggers on Select (and more) Apr 28, 2021
@oliviertassinari
Copy link
Member

We have moved the issue to #25578.

#12034 was solved with the support of React portals, but we recently broke it again by moving the click away trigger from mouseup to click.

@Pabriuz
Copy link

Pabriuz commented Oct 6, 2021

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)

Thank you so much for your approach, it helped me work with mine.

Here's what i did, maybe can help someone:
On the click away event

if (event.target.localName === 'body')
    event.preventDefault();

@dapize
Copy link

dapize commented Dec 28, 2021

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)

Thank you so much for your approach, it helped me work with mine.

Here's what i did, maybe can help someone: On the click away event

if (event.target.localName === 'body')
    event.preventDefault();

adding other case where we are using the onCLickAway function like this (getted from the Menu UI Demo doc page);

const onClickAwayCallBack = (event) => {
    if (anchorRef.current && anchorRef.current.contains(event.target)) {
      return;
    }

    setOpen(false);
  };

just we have to add the 'return' instead of 'event.preventDefault();' like this;

const onClickAwayCallBack = (event) => {
    if (event.target.localName === 'body') {
       return;
    }
    if (anchorRef.current && anchorRef.current.contains(event.target)) {
      return;
    }

    setOpen(false);
  };

thank you @Pabriuz for the help

@chriszrc
Copy link

chriszrc commented Jan 26, 2022

Isn't this all solved now with disableReactTree={true}? Wrapping the select with that option and checking for body is working for me-

[EDIT] - spoke too soon, also needed to check that clicks were on the backdrop and not the select contents:

if (
          target.localName === "div" &&
          target?.className.indexOf("MuiBackdrop-root") > -1
) {
          setSelectOpen(false);
 }

https://mui.com/api/click-away-listener/

@GabrielBrandaoProjetos
Copy link

Definir mouseEventa propriedade como 'onMouseUp'in ClickAwayListenerfuncionou para mim.

Muito obrigado, funcionou pra mim.

@romanown
Copy link

romanown commented Jul 28, 2023

if (event.target.localName === 'body') {
return;
}
it helped for me as show abowe. but it is bag. mui v.4.

@nmt308
Copy link

nmt308 commented May 18, 2024

Setting mouseEvent property to 'onMouseUp' in ClickAwayListener worked for me.

It worked for me, save my life

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: ClickAwayListener The React component component: select This is the name of the generic UI component, not the React module!
Projects
None yet
Development

No branches or pull requests