user11607572
user11607572

Reputation: 203

Select, OutlineInput label with shrink property not same as TextField when empty

If I use a TextField component, and set InputLabelProps={{shrink: true}}, the Label stays at the top of the TextField, and the outline is cut to show the Label correctly.

However, if I use Select component, as follows :

<FormControl variant={ this.props.variant }  className={ classes.formControl } fullWidth>
            <InputLabel
                ref={ (input) =>{ this.inputLabel = input }}
                htmlFor={ this.props.id }
                shrink={ true }>
                { this.props.label }
            </InputLabel>
            <Select
                id={ this.props.id }
                value={ this.props.value }
                onChange={ this.onChange }
                input={
                    <OutlinedInput
                        labelWidth={ this.state.labelWidth }
                        name={ this.props.id }
                        id={ this.props.id }
                    />
                    }
                >
                { this.props.options.map(option => (
                    <MenuItem key={ option.value } value={ option.value }>
                        <em>{ option.label }</em>
                    </MenuItem>
                ))}
            </Select>
        </FormControl>

The Label stays at the top of the outline just like TextField, however, the outline is not cut out to display the Label nicely, instead it looks like it is "crossed out"

What am I doing wrong? (Please not, that the this.state.labelWidth has a correct value, even if I hard code this, it still does not work)

Thanks in advance for your help Cheers Jason

Upvotes: 18

Views: 24418

Answers (4)

Atharva Upadhye
Atharva Upadhye

Reputation: 1

hope this helps :)

<FormControl fullWidth>
    <InputLabel shrink>Label</InputLabel>
    <Select label="Label" defaultValue={undefined} notched>
        <MenuItem value="1">One</MenuItem>
        <MenuItem value="2">Two</MenuItem>
    </Select>
</FormControl>
<TextField
    label="Label"
    slotProps={{
        inputLabel: {
        shrink: true,
        },
    }}
/>

https://stackblitz.com/edit/vitejs-vite-jsxsscjo?file=src%2FApp.tsx

Upvotes: 0

cmateusmoraes
cmateusmoraes

Reputation: 41

To work correctly without cutting the label you must use the InputLabel component, reference it in the labelId of the Select component and repeat the Select label in the Select parameter.

See below:

<FormControl fullWidth>
  <InputLabel id="demo-simple-select-label">Age</InputLabel>
  <Select labelId="demo-simple-select-label" id="demo-simple-select" value={age} label="Age" onChange={handleChange}>
    <MenuItem value={10}>Ten</MenuItem>
    <MenuItem value={20}>Twenty</MenuItem>
    <MenuItem value={30}>Thirty</MenuItem>
  </Select>
</FormControl>

Note that the select label "Age" is inside the InputLabel component and is repeated in the Select label property.

See the docs: https://mui.com/material-ui/react-select/

Upvotes: 0

Ryan Cogswell
Ryan Cogswell

Reputation: 81106

The default behavior is for the shrink property of InputLabel to be automatically managed by Material-UI. Generally shrink is only applied when the Select has a non-empty value or when it has focus. If you want to have shrink applied all the time, then you also need to specify notched on OutlinedInput (in v4, on Select for v5) since that is what controls leaving a space for the label along the outline.

The v4 code below (v5 example further down) shows both cases (1. always apply shrink and notched, 2. let MUI manage shrink and notched):

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
  },
  selectEmpty: {
    marginTop: theme.spacing(2)
  }
}));

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
          shrink
          ref={inputLabel}
          htmlFor="outlined-age-always-notched"
        >
          Age
        </InputLabel>
        <Select
          value={values.age}
          onChange={handleChange}
          input={
            <OutlinedInput
              notched
              labelWidth={labelWidth}
              name="age"
              id="outlined-age-always-notched"
            />
          }
        >
          <MenuItem value="">
            <em>None</em>
          </MenuItem>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
      <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;

Edit Outlined Select

Here's a similar v5 example which is simpler due to not needing to specify the input component explicitly:

import * as React from "react";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select, { SelectChangeEvent } from "@mui/material/Select";

export default function BasicSelect() {
  const [age, setAge] = React.useState("");

  const handleChange = (event: SelectChangeEvent) => {
    setAge(event.target.value as string);
  };

  return (
    <>
      <FormControl sx={{ minWidth: 120, margin: 1 }}>
        <InputLabel shrink id="demo-simple-select-label">
          Age
        </InputLabel>
        <Select
          notched
          labelId="demo-simple-select-label"
          id="demo-simple-select"
          value={age}
          label="Age"
          onChange={handleChange}
        >
          <MenuItem value="">
            <em>None</em>
          </MenuItem>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
      <FormControl sx={{ minWidth: 120, margin: 1 }}>
        <InputLabel id="demo-simple-select-label2">Age</InputLabel>
        <Select
          labelId="demo-simple-select-label2"
          id="demo-simple-select2"
          value={age}
          label="Age"
          onChange={handleChange}
        >
          <MenuItem value="">
            <em>None</em>
          </MenuItem>
          <MenuItem value={10}>Ten</MenuItem>
          <MenuItem value={20}>Twenty</MenuItem>
          <MenuItem value={30}>Thirty</MenuItem>
        </Select>
      </FormControl>
    </>
  );
}

Edit shrink Select label

Upvotes: 27

Manny Alvarado
Manny Alvarado

Reputation: 1233

Last answer has a deprecated prop labelWidth

For the newer MUI just add shrink prop to InputLabel component and notched prop to Select component.

More on the issue and solution here. https://github.com/mui/material-ui/issues/22799

Upvotes: 9

Related Questions