Search code examples
cssreactjswidthmaterial-uihtml-select

Material-UI How to set minWidth and maxWidth of MenuItem (popover) according to the width of the select component


The width of the popover, to be precise. No matter how long the text of menu item is, I want the width of the popover always the same as the select component. Set the autoWidth to true or false is not helping.

following are code for the select component:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import OutlinedInput from '@material-ui/core/OutlinedInput';
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 => ({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120,
  },
}));

function SimpleSelect() {
  const classes = useStyles();
  const [values, setValues] = React.useState({
    age: '',
  });

  const inputLabel = React.useRef(null);
  const [labelWidth, setLabelWidth] = React.useState(0);
  React.useEffect(() => {
    setLabelWidth(inputLabel.current.offsetWidth);
  }, []);

  function handleChange(event) {
    setValues(oldValues => ({
      ...oldValues,
      [event.target.name]: event.target.value,
    }));
  }

  return (
    <form className={classes.root} autoComplete="off">
      <FormControl variant="outlined" className={classes.formControl}>
        <InputLabel ref={inputLabel} htmlFor="outlined-age-simple">
          Age
        </InputLabel>
        <Select
          value={values.age}
          onChange={handleChange}
          input={<OutlinedInput labelWidth={labelWidth} name="age" id="outlined-age-simple" />}
        >
          <MenuItem value="">
            <em>None</em>
          </MenuItem>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
    </form>
  );
}

export default SimpleSelect;

How can I achive this?


Solution

  • You can achieve this by setting an explicit width on the menu items that is the same as the width for the form control.

    Below is an example:

    import React from "react";
    import { makeStyles } from "@material-ui/core/styles";
    import InputLabel from "@material-ui/core/InputLabel";
    import MuiMenuItem from "@material-ui/core/MenuItem";
    import FormControl from "@material-ui/core/FormControl";
    import Select from "@material-ui/core/Select";
    
    const selectWidth = 150;
    
    const useStyles = makeStyles(theme => ({
      root: {
        display: "flex",
        flexWrap: "wrap"
      },
      formControl: {
        margin: theme.spacing(1),
        width: selectWidth
      },
      selectEmpty: {
        marginTop: theme.spacing(2)
      }
    }));
    
    const useMenuItemStyles = makeStyles(theme => ({
      menuItem: {
        width: selectWidth
      }
    }));
    
    function MenuItem(props) {
      const classes = useMenuItemStyles(props);
      return <MuiMenuItem className={classes.menuItem} {...props} />;
    }
    
    function SimpleSelect() {
      const classes = useStyles();
      const [values, setValues] = React.useState({
        age: ""
      });
    
      function handleChange(event) {
        setValues(oldValues => ({
          ...oldValues,
          [event.target.name]: event.target.value
        }));
      }
    
      return (
        <form className={classes.root} autoComplete="off">
          <FormControl className={classes.formControl}>
            <InputLabel htmlFor="age-simple">Age</InputLabel>
            <Select
              value={values.age}
              onChange={handleChange}
              inputProps={{
                name: "age",
                id: "age-simple"
              }}
            >
              <MenuItem value="">
                <em>None</em>
              </MenuItem>
              <MenuItem value={10}>Ten</MenuItem>
              <MenuItem value={20}>Twenty</MenuItem>
              <MenuItem value={30}>Thirty</MenuItem>
            </Select>
          </FormControl>
        </form>
      );
    }
    
    export default SimpleSelect;
    

    Edit Material demo

    If you want the width of the Select to be dynamic based on the width of the widest menu item, then the solution is a fair amount more complicated.