Search code examples
javascriptreactjsdrop-down-menumaterial-ui

MUI Select component menu takes 2 clicks to open when another Select component's menu is open


I'm working on an app that has two dropdowns (Select components) displayed beside each other (I will refer to them as A and B).

Suppose A is open and the user wants to click and open B. I've noticed that by default, material UI requires the user to do this in two clicks; 1 click to close A, followed by 1 click to open B.

A similar issue was brought up in this thread for the Menu component: https://github.com/mui/material-ui/issues/11243

It seems like the click event isn't bubbling up.

Is it possible to override this behavior?

My code:

import { InputLabel, MenuItem, FormControl, Select } from '@mui/material';

const Dropdown = ({ value, label, options, setter }) => {

    const handleChange = (event) => {
        const selectedValue = event.target.value;
        setter(selectedValue);
    };

    return (
        <FormControl
            variant='outlined'
            size="small"
            sx={{
                minWidth: "120px",
                backgroundColor: "#eb6060",
                borderRadius: "5px",
                border: "1px solid black",
                // Remove blue outline on dropdown when user clicks on dropdown
                '& .MuiOutlinedInput-notchedOutline': {
                    border: 'none',
                },
            }}
        >
            <InputLabel
                shrink={false} // prevent label from shrinking to top-left corner when user clicks on dropdown
                sx={{
                    // prevent blue highlight on label text when user clicks on dropdown
                    color: "black",
                    opacity: 0.6,
                    "&.Mui-focused": {
                        color: "black",
                        opacity: 0.6,
                    },
                    
                }}
            >
                {value === "" ? label : ""}
            </InputLabel>
            <Select
                onChange={handleChange}
                label={value === "" ? label : ""}
                value={value}
                onClose={() => {
                    setTimeout(() => {
                      document.activeElement.blur();
                    }, 0);
                }}
                sx={{
                    "&:hover": {
                        backgroundColor: "#b34b4b",
                    },
                    "&.Mui-focused": {
                        backgroundColor: "#b34b4b",
                    },
                }}
            >
                {options.map((option) => (
                    <MenuItem
                        key={option.code}
                        value={option.code}
                        sx={{
                            // Remove keyboard focus highlight on dropdown options
                            "&.Mui-focusVisible": {
                                backgroundColor: "white",
                            },
                            // Add hover highlight on dropdown options
                            "&.MuiMenuItem-root:hover": {
                                backgroundColor: "#D3D3D3",
                            }
                        }}
                    >
                        {option.alias}
                    </MenuItem>
                ))}
            </Select>
        </FormControl>
    );
};

export default Dropdown;

Solution

  • It was a bit hacky but I don't know other approach. How the dropdown works: when you open it, an invisible backdrop with a high z-index is added covering everything except the options, and when its clicked the dropdown is closed, that's why you can click anywhere in the page and it will close because you are clicking the invisible backdrop. What I did was to add a z-index higher than the backdrop, so the dropdown stays in front and becomes clickable. But only this would have both dropdowns opened in the same time, so I added a code in the onOpen, to click the current backdrop and close it before opening the new one:

    https://codesandbox.io/s/quirky-black-mr6c52?file=/src/Dropdown.js

    Dropdown.js

    import { InputLabel, MenuItem, FormControl, Select } from "@mui/material";
    
    const Dropdown = ({ value, label, options, setter }) => {
      const handleChange = (event) => {
        const selectedValue = event.target.value;
        setter(selectedValue);
      };
    
      return (
        <FormControl
          variant="outlined"
          size="small"
          sx={{
            minWidth: "140px",
            backgroundColor: "#eb6060",
            borderRadius: "5px",
            border: "1px solid black",
            zIndex: 1350, // 🟥 zIndex to be on top of backdrop
            "& .MuiOutlinedInput-notchedOutline": {
              border: "none"
            }
          }}
        >
          <InputLabel
            shrink={false} // prevent label from shrinking to top-left corner when user clicks on dropdown
            sx={{
              // prevent blue highlight on label text when user clicks on dropdown
              color: "black",
              opacity: 0.6,
              "&.Mui-focused": {
                color: "black",
                opacity: 0.6
              }
            }}
          >
            {value === "" ? label : ""}
          </InputLabel>
          <Select
            onChange={handleChange}
            label={value === "" ? label : ""}
            value={value}
            // 🟥 Click on current backdrop to close the current dropdown
            onOpen={() => {
              document.querySelector(".MuiModal-backdrop")?.click();
            }}
            onClose={() => {
              setTimeout(() => {
                document.activeElement.blur();
              }, 0);
            }}
            sx={{
              "&:hover": {
                backgroundColor: "#b34b4b"
              },
              "&.Mui-focused": {
                backgroundColor: "#b34b4b"
              }
            }}
          >
            {options.map((option) => (
              <MenuItem
                key={option.code}
                value={option.code}
                sx={{
                  // Remove keyboard focus highlight on dropdown options
                  "&.Mui-focusVisible": {
                    backgroundColor: "white"
                  },
                  // Add hover highlight on dropdown options
                  "&.MuiMenuItem-root:hover": {
                    backgroundColor: "#D3D3D3"
                  }
                }}
              >
                {option.alias}
              </MenuItem>
            ))}
          </Select>
        </FormControl>
      );
    };
    
    export default Dropdown;