'How to I keep a Material-ui Select open when I click on only one of the items in it

I have been writing a custom Material-UI Select dropdown which has an optional text field at the top to allow the user to search / filter items in the Select if there were many entries.

I am struggling with how to keep the Select open when I click on the text field (rendered as an InputBase) and just have the normal behavior (of closing the Select when a regular MenuItem is selected.

CodeSandbox here : https://codesandbox.io/s/inspiring-newton-9qsyf

 const searchField: TextField = props.searchable ? (
    <InputBase
      className={styles.searchBar}
      onClick={(event: Event) => {
        event.stopPropagation();
        event.preventDefault();
      }}
      endAdornment={
        <InputAdornment position="end">
          <Search />
        </InputAdornment>
      }
    />
  ) : null;

  return (
    <FormControl>
      <Select
        className={styles.root}
        input={<InputBase onClick={(): void => setIconOpen(!iconOpen)} />}
        onBlur={(): void => setIconOpen(false)}
        IconComponent={iconOpen ? ExpandMore : ExpandLess}
        {...props}
      >
        {searchField}
        {dropdownElements.map(
          (currEntry: string): HTMLOptionElement => (
            <MenuItem key={currEntry} value={currEntry}>
              {currEntry}
            </MenuItem>
          )
        )}
      </Select>
    </FormControl>
  );

As you can see above I've tried using stopPropagation and preventDefault but to no avail.



Solution 1:[1]

check out this codesandbox link: https://codesandbox.io/s/busy-paper-9pdnu

You can use open prop of Select API

Solution 2:[2]

I was able to make a controlled open select by providing open prop as a react state variable and implementing correct event handlers. To make it controlled you must provide onOpen and onClose props of the Select and make sure the open prop stays true when the custom textfield is clicked.

One more important thing I had to do was override the default keyDown behavior of the Select component. If you open up a Select and start typing into it, it shifts focus to the select option that matches what you are typing. For example, if you Select had an option with the text Foobar and if you start typing Food and water, it would cause focus to shift from your custom text input onto the Foobar option. This behavior is overridden in the onKeyDown handler of the custom textfield

Working sandbox here

Edit: even though this worked in the codepen, I had to add onChange={handleOpen} to the Select as well to get it working on a real browser with React and Next.

Solution 3:[3]

You can still using stopPropagation to make it work

// open state
const [isSelectorOpen, setisSelectorOpen] = useState(false)

// handle change
const handleChange = event => {
  const { value } = event.target
  event.stopPropagation()
  // set your value
}

// selector
<Select
  multiple
  open={isSelectorOpen}
  onChange={handleChange}
  input={(
    <Input
      onClick={() => setisSelectorOpen(!isSelectorOpen)}
    />
  )}
  // other attribute
>
  <MenuItem>a</MenuItem>
  <MenuItem>b</MenuItem>
  <MenuItem>c</MenuItem>
</Select>

Solution 4:[4]

In my case, none of the above worked, but this did the trick to stop closing the Select:

<MenuItem
    onClickCapture={(e) => {
         e.stopPropagation();
    }}>

You can also change onMouseEnter to change some default styling that comes with using MenuItem (like pointer cursor when mouse enters its layout)

onMouseEnter={(e) => {
          e.target.style.backgroundColor = "#ffffff";
          e.target.style.cursor = "default";
    }}

In my case i also needed to remove the grey clicking effect that MenuItem makes on click, which is a new object generated in MuiTouchRipple-root, so changing display to none did the trick.

sx={{
   "& .MuiTouchRipple-root": {
       display: "none",
    },
 }}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nihal Saxena
Solution 2
Solution 3 BaalWu
Solution 4 Mitchy