Search code examples
reactjsselectdrop-down-menumaterial-ui

React - MUI dropdown with display value other than selected


I try to achieve a dropdown that displays multiple buttons for selection and a display value independent of the drop-down items like so:

enter image description here

In this example, the user can select different scales for a chart that displays two metrics. In case both metrics have different scales, the drop-down shows "mixed" in case they both have the same scale it shall show either "linear" or "log", depending on the overall scale.

I tried with MUI Select component and added a custom function to change the display value, but I get the warning:

MUI: You have provided an out-of-range value `linear` for the select component.

Consider providing a value that matches one of the available options or ''.

Here my code snippets:

const displayMetricScale = () => {
    return (scale_metric1===scale_metric2) ? (scale_metric1) : "mixed";
};

<Select
    label="Scale"
    value={displayMetricScale()}
    defaultValue="mixed"
    renderValue={(p) => p}
>
    <MenuItem>
    <FormControl>
        <FormLabel>Metric 1</FormLabel>
        <Button onClick={changeScaleLin} >
            Linear
        </Button>
        <Button onClick={changeScaleLog} >
            Logarithmic
        </Button>
    </FormControl>
    </MenuItem>
    <MenuItem>
    <FormControl>
        <FormLabel>Metric 2</FormLabel>
        <Button onClick={changeScaleLin} >
            Linear
        </Button>
        <Button onClick={changeScaleLog} >
            Logarithmic
        </Button>
    </FormControl>
    </MenuItem>
</Select>

Solution

  • There are 2 things I would like to suggest here:

    First:

    Add a value prop to each menuItem. This way they can be "matched" by the Select component as valid selections. Like so:

    <MenuItem value="linear">
      ... 
    </MenuItem>
    <MenuItem value="log">
      ...
    </MenuItem>
    

    This should hopefully get rid of the warning you have mentioned in your question.

    Second:

    The second problem you need to solve is to have "mixed" be a valid selection item.

    A solution could be to show "mixed" when there is no selection. This solution isn't ideal and not scalable to any more than 1 custom item, but might work for you. The comments in the code should explain better what I am trying to put forth:

    const displayMetricScale = () => {
      // Return empty when you want to show "mixed"
      return (scale_metric1===scale_metric2) ? (scale_metric1) : "";
    };
    
    <Select
      label="Scale"
      value={displayMetricScale()}
      displayEmpty=true // To be able to show a value when value is empty
      renderValue={(p) => p === "" ? "mixed" : p} // If p is empty, show "mixed"
    >
    

    Disclaimer: I haven't tested this code so it may have problems but I have a hunch it will work