'Material-UI - Apply max-height to Select children

I am using the Material-UI react library to render some Dropdown menus, using the <FormControl>, <Select> and <MenuItem> components. The options array for this dropdown menu is quite large, and I would like to set a max-height on the dropdown, so it does not become to large. I am currently struggling to do this, as I will explain below.

basic dropdown using Material-UI:

const MenuValidNotes = ({
  schedule,
  indexTrack,
  indexSchedule,
  actionSetTrackScheduleItemNote,
}) => {

  const listNotesMenu = () => (
    ARRAY_VALID_NOTES.map((noteObj, i) => (
      <MenuItem
        value={noteObj.note}
        key={`track-item-${indexTrack}-schedule-${indexSchedule}-note-${i}`}
        onClick={() => actionSetTrackScheduleItemNote(indexTrack, indexSchedule, noteObj.midiNumber)}
      >{noteObj.note}</MenuItem>
    ))
  )

  return(
    <div>
      <FormControl>
        <InputLabel>Note</InputLabel>
        <Select
          defaultValue={noteValueToNoteObject(schedule.noteValue).note}
        >
          {listNotesMenu()}
        </Select>
      </FormControl>
    </div>  
  )
}

One way I found to set the max-height is to render the children of <Select> in a div, give it a classname and apply some CSS to it.

However, the <Select> component requires that its children are <MenuItem>s, so having a <div> around will break value attribute, which means it would not display the correct value. (found this while reading Material-UI Select e.target.value is undefined)

  const listNotesMenu = () => (
    ARRAY_VALID_NOTES.map((noteObj, i) => (
      <div className="..."> // this div will break the 'value' of the Select component 
         <MenuItem ... />
      </div>
    ))
  )

so, ideally, I would like to be able to control both the value and the max-height of its children. Is this possible at all? The Material-UI docs on select have no such example, and the props list of the <Select component does not include any fields to control the height. Thank you for your help.

(The screenshots above displays this issue. one screenshot shows that it is possible to control the max-height using a div wrapper, but that breaks the value; the other shows the dropdown without the div wrapper, which means we can't set max-height).

enter image description here

enter image description here

enter image description here



Solution 1:[1]

The height that you want to control is the Paper element rendered by the Popover element within Menu.

The default styles are maxHeight: 'calc(100% - 96px)'.

Below is one example of how to override this in v4 of Material-UI (v5 example further down):

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";

const useStyles = makeStyles(theme => ({
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120
  },
  selectEmpty: {
    marginTop: theme.spacing(2)
  },
  menuPaper: {
    maxHeight: 100
  }
}));

const VALID_NOTES = [
  "C",
  "C#",
  "D",
  "D#",
  "E",
  "F",
  "F#",
  "G",
  "G#",
  "A",
  "A#",
  "B"
];
export default function SimpleSelect() {
  const classes = useStyles();
  const [note, setNote] = React.useState("");

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

  return (
    <div>
      <FormControl className={classes.formControl}>
        <InputLabel id="demo-simple-select-label">Note</InputLabel>
        <Select
          labelId="demo-simple-select-label"
          id="demo-simple-select"
          value={note}
          onChange={handleChange}
          MenuProps={{ classes: { paper: classes.menuPaper } }}
        >
          {VALID_NOTES.map(validNote => (
            <MenuItem value={validNote}>{validNote}</MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

Edit max height for Select items

The key aspect being MenuProps={{ classes: { paper: classes.menuPaper } }} and the definition of the menuPaper styles.


Below is a similar example, but for v5 of Material-UI. This example leverages the new sx prop for the styling.

import React from "react";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";

const VALID_NOTES = [
  "C",
  "C#",
  "D",
  "D#",
  "E",
  "F",
  "F#",
  "G",
  "G#",
  "A",
  "A#",
  "B"
];
export default function SimpleSelect() {
  const [note, setNote] = React.useState("");

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

  return (
    <div>
      <FormControl sx={{ m: 1, minWidth: 120 }} variant="standard">
        <InputLabel id="demo-simple-select-label">Note</InputLabel>
        <Select
          labelId="demo-simple-select-label"
          id="demo-simple-select"
          value={note}
          onChange={handleChange}
          MenuProps={{ PaperProps: { sx: { maxHeight: 100 } } }}
        >
          {VALID_NOTES.map((validNote) => (
            <MenuItem value={validNote}>{validNote}</MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

Edit max height for Select items

Solution 2:[2]

2022 Answer Using MUI 4.12

In case this is helpful to you, neither of the above answers were correctly structured for our use case. I found that you only need to access the MenuProps on the Select component. Like this:

<Select
...
   MenuProps={{
      style: {
         maxHeight: 400,
            },
      }}
>
</Select>

Solution 3:[3]

There is a section in MUI docs that has examples of Select with limited height. You can set the height of Paper, which is a container of all dropdown items in the Menu, which is a popover of the Select using MenuProps like this:

// the MenuItem height is a bit different between xs and larger breakpoints
const ITEM_HEIGHT = 36;
const MOBILE_ITEM_HEIGHT = 48;

const ITEM_PADDING_TOP = 8;
const MENU_ITEMS = 3; // change this to your preference.
<Select
  MenuProps={{
    PaperProps: {
      sx: {
        maxHeight: {
          xs: MOBILE_ITEM_HEIGHT * MENU_ITEMS + ITEM_PADDING_TOP,
          sm: ITEM_HEIGHT * MENU_ITEMS + ITEM_PADDING_TOP
        },
        width: 250
      }
    }
  }}
  {...}
/>

Live Demo

Codesandbox Demo

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
Solution 2
Solution 3 NearHuscarl