Repository: mui/material-ui (TypeScript)
Date: 2019-09-03 20:24:19+00:00
Task type: Bug Fix

Issue:
Select doesn't support variant="outlined"
So in the docs of `Select` component we can choose from either `standard`, `outlined` or `filled` variants
```
<Select variant='outlined' />
```

However by default adding `outlined` doesn't change a thing on the component visuall, except that it receives `outlined` class.

There is this another issue https://github.com/mui-org/material-ui/issues/13049 where this has been discussed but I think hasn't been actually addressed properly.

In the previous issue it's claimed that the implementation is correct and only documentation needs fixing. Documentation indeed was updated but in the example author uses `OutlinedInput` which is manually passed to `Select`. IMO this is incorrect because as a user I expect that `variant="outlined"` would just work without me needing to do that manual labor of passing `Input` manually.

This is how at least `TextField` component works, you just pass variant and it works.

## Expected Behavior 🤔

```
<Select variant='outlined' />
```

Should render something like this:
![image](https://user-images.githubusercontent.com/437214/51248893-39fc3a00-199a-11e9-87fe-0c01cd18e51c.png)

## Current Behavior 😯

No outlined is rendered by default:
![image](https://user-images.githubusercontent.com/437214/51248915-4c767380-199a-11e9-8406-d5e8dca091a6.png)


## Steps to Reproduce 🕹

Link:

https://codesandbox.io/s/jl7nm4no0y



Issue discussion:
Expected behavior because it is documented as such: https://material-ui.com/api/select/#props

The documentation also claims to spread props to `Input` which is only true for default behavior. Not when `input={<OtherElement />}` is used.
Sorry, I'm confused - how is that expected behavior? What does `variant='outlined'` do anyways?
> Sorry, I'm confused - how is that expected behavior? What does `variant='outlined'` do anyways?

No I mean you're right in assuming it's expected. I was just adding a source to justify that claim.
So what should be the next steps for this?
This is what I would do:
1. remove implementation that handles `variant` in `Select.js`
2. See if tests break
3. Check if this prop was used in the docs and if the removal changed the visuals
4. Get back with results
5. Discuss how we reconcile the API 
Shouldn't it be done other way around - by implementing proper rendering for outlined and filled versions when a variant property is passed?
I don't have a strong opinion on how you do it. It might not matter.
@oliviertassinari Why do you not consider this a bug?
@eps1lon From what I understand, it's first a documentation issue, where you can't guess the right API without looking at the demos. Now, we can either improve the documentation or the API. I think that we should try to improve the API, if not possible, fallback to the documentation.
The variant property is used by the Select to change "some" of the style.
> The variant property is used by the Select to change "some" of the style.

But not the style it's intended to do. It documents itself as a switch for the used input variant. It has the exact same wording as variant on `TextField`. So the documentation is either wrong here or the implementation. 
@eps1lon The documentation is wrong. We have never tried to make it work like this.
@oliviertassinari don't you think that even if we fixed documentation it would still be wrong? I mean if we look at unification across all components, then the way `variant` currently works for `Select` doesn't make any sense.
I.e.: `TextField variant="outlined"` will render you properly what you expect - outlined text field. So even if we fix documentation for select to reflect that variant doesn't work as one may think, it will still be incorrect if we consider whole library and not this single instance
@bytasv Yes, I do think that we should work on improving the API.
What's worse, is that the documentation for producing an actual outlined select requires the use of 'ref' to control 'labelWidth' on OutlinedInput.  MUI's Typescript definitions don't support the ref property at all.  Ideally, 'variant' would work like TextField or be removed all together.

https://material-ui.com/demos/selects/

```jsx
  <FormControl variant="outlined" className={classes.formControl}>
          <InputLabel
            **ref={ref => {
              this.InputLabelRef = ref;
            }}**
            htmlFor="outlined-age-simple"
          >
            Age
          </InputLabel>
          <Select
            value={this.state.age}
            onChange={this.handleChange}
            input={
              <OutlinedInput
                **labelWidth={this.state.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>
```

I've encountered the same issue with `Select` component. As the document suggests, I expect the declare `variant = filled | outlined` is enough but it's not, `variant` prop is kind of useless at the moment, you have to pass `FilledInput` or `OutlinedInput` as `input` prop for the right look and feel.

However, when `SelectInput` component handles its styles and classnames, it still refer to the `variant` props to determine which classnames to apply to the component.

As the result, to be able to customise an outlined / filled select, we need to use both `input` and variant props at the same time, something like:

```javascript
<Select
       variant="outlined"
       classes={{ outlined: outlinedClassName}}
       input={<OutlinedInput />}
 />
```

I reckon we can use the same implementation `TextField` component is using at the moment to resolve / improve this problem. I am happy to make a PR if necessary. What do you think @oliviertassinari ?
Also encountering this issue. I'm able to get the `<Select>` outlined by using an `OutlinedInput`, but it's quite ugly and doesn't seem to have consistent behavior with the `variant="outlined"` property on `TextField`
@t49tran Are you still up for a PR? Looks like quite a few others would be interested.

> I reckon we can use the same implementation `TextField` component is using at the moment to resolve / improve this problem. I am happy to make a PR if necessary. What do you think @oliviertassinari ?


@skirunman, not sure what is the core team's opinion on this but if people are keen on this I can submit a PR this week.
@t49tran I can't speak for anyone, but @oliviertassinari did say above 

> Yes, I do think that we should work on improving the API.

So sounds like to me they are receptive.
@skirunman, I am happy to do a PR but if you are seriously keen on doing this one yourself I am happy to pass it over.
@t49tran This PR is all you, thanks.
@taschetto, yes if you could I am really appreciated. I am quite busy with other life stuff at the moment.
I would probably do:

```jsx
      <TextField
        select
        variant="outlined"
        value={values.age}
        onChange={handleChange}
        inputProps={{ 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>
      </TextField>
```

https://codesandbox.io/s/yqy753v80j

![Capture d’écran 2019-04-29 à 15 25 13](https://user-images.githubusercontent.com/3165635/56899132-0188f380-6a93-11e9-8daf-a893e6b7ea84.png)

anytime I need to use the outlined variant.

@t49tran Let me see if we can improve the situation. Hold on.
@oliviertassinari We use `TextField` with `select` prop when we need a simple select. However, we have built more complex selects where this does not work. We have implemented our own logic to deal with `outlined` variant, but I still believe the `Select` component should support this directly.
I see a couple of possible solutions:

1. We replicate the TextField behavior. We make the Select component pick its own input component (Input, OutlinedInput, FilledInput) based on the variant prop. This increases the bundle size cost of importing the Select. We would need to open a "test" pull request to evaluate the bundle size drawback (I have no idea of the magnitude, 10%, 20%, +)
2. We replicate the input behavior. We create as many select components as input variants we have: Select, OutlinedSelect, FilledSelect, NativeSelect, NativeOutlineSelect, NativeFilledSelect. This would avoid the above bundle size issue. The current Select component is close to a HOC, it enhances the provided input.
3. We remove the `variant` prop from the select not to confuse people, find a way to change the select style based on the parent variant.
4. else?

What option do you guys prefer?
I'd vote 1 and then 3 as a backup. I don't think bundle size will change much with 1.  2. does not make sense to me and does not seem to follow patterns elsewhere in MUI.

Our custom select just supports `outlined` and `standard` variants and uses example as per this code snippet. 

```
  const inputLabel = React.useRef(null);
  const [labelWidth, setLabelWidth] = React.useState(0);
  React.useEffect(() => {
    setLabelWidth(inputLabel.current.offsetWidth);
  }, [inputLabel]);

  return (
    <FormControl className={classes.root} fullWidth={fullWidth} margin={margin} required={required} variant={variant}>
      <InputLabel
        htmlFor="select-multiple-chip"
        ref={inputLabel}
        shrink={label && (!!placeholder || value !== undefined)}
      >
        {label}
      </InputLabel>
      <Select
        input={
          variant === 'outlined' ? (
            <OutlinedInput id="select-multiple-chip" labelWidth={labelWidth} notched={Boolean(label)} />
          ) : (
            <Input id="select-multiple-chip" />
          )
        }
        ref={inputLabel}
...
```
> I don't think bundle size will change much with 1.

@skirunman The bundle size change isn't due to the additional code directly in `Select` (which wouldn't be much), but because `Select` would need to import `FilledInput` and `OutlinedInput`, so even if your code isn't using those variants, importing `Select` would then bring in all of that code to your bundle.

@oliviertassinari Option 1 definitely would be the best DX. From a practical standpoint, the bundle size cost would only be a change for people using `Select` who are **not** using `TextField` at all.

I'm happy to try option 1 out.
I would vote for 1 too.
Any update on this? 
I would also prefer option 1 and really looking forward to this!
@warreee It's just waiting for someone to do a pull request. The most recent person to express interest in working on it was @taschetto. 

@taschetto Are you still interested in working on a pull request for this?


@ryancogswell Unfortunately I won't be able to push this
When using `filled` as default variant (which is now the default encouraged by material design), this is biting me, too.
> I see a couple of possible solutions:
> 
> 1. We replicate the TextField behavior. We make the Select component pick its own input component (Input, OutlinedInput, FilledInput) based on the variant prop. This increases the bundle size cost of importing the Select. We would need to open a "test" pull request to evaluate the bundle size drawback (I have no idea of the magnitude, 10%, 20%, +)

I would like to open a pr following this strategy, that's ok?


@netochaves Yes, it's all yours :) 
What you guys think about this:
```js
<InputLabel ref={inputLabel} htmlFor="outlined-age-simple">
    Age
</InputLabel>
<Select
  value={values.age}
  onChange={handleChange}
  variant="outlined"
  labelWidth={labelWidth}
  inputProps={{ name: 'age', id: 'outlined-age-simple' }}
>
```
Output:
![image](https://user-images.githubusercontent.com/19830660/64134125-8f624b80-cdb1-11e9-8a3f-0afbb56d32f6.png)

Perhaps we should handle label inside `Select` like `TextField`does, but i think this should be another issue/pr.

Solution patch:
diff --git a/docs/pages/api/select.md b/docs/pages/api/select.md
--- a/docs/pages/api/select.md
+++ b/docs/pages/api/select.md
@@ -29,8 +29,9 @@ You can learn more about the difference by [reading our guide](/guides/minimizin
 | <span class="prop-name">classes</span> | <span class="prop-type">object</span> |  | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
 | <span class="prop-name">displayEmpty</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, a value is displayed even if no items are selected.<br>In order to display a meaningful value, a function should be passed to the `renderValue` prop which returns the value to be displayed when no items are selected. You can only use it when the `native` prop is `false` (default). |
 | <span class="prop-name">IconComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">ArrowDropDownIcon</span> | The icon that displays the arrow. |
-| <span class="prop-name">input</span> | <span class="prop-type">element</span> | <span class="prop-default">&lt;Input /></span> | An `Input` element; does not have to be a material-ui specific `Input`. |
+| <span class="prop-name">input</span> | <span class="prop-type">element</span> |  | An `Input` element; does not have to be a material-ui specific `Input`. |
 | <span class="prop-name">inputProps</span> | <span class="prop-type">object</span> |  | [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes) applied to the `input` element. When `native` is `true`, the attributes are applied on the `select` element. |
+| <span class="prop-name">labelWidth</span> | <span class="prop-type">number</span> | <span class="prop-default">0</span> | The label width to be used on OutlinedInput. This prop is required when the `variant` prop is `outlined`. |
 | <span class="prop-name">MenuProps</span> | <span class="prop-type">object</span> |  | Props applied to the [`Menu`](/api/menu/) element. |
 | <span class="prop-name">multiple</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If true, `value` must be an array and the menu will support multiple selections. |
 | <span class="prop-name">native</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the component will be using a native `select` element. |
@@ -41,7 +42,7 @@ You can learn more about the difference by [reading our guide](/guides/minimizin
 | <span class="prop-name">renderValue</span> | <span class="prop-type">func</span> |  | Render the selected value. You can only use it when the `native` prop is `false` (default).<br><br>**Signature:**<br>`function(value: any) => ReactElement`<br>*value:* The `value` provided to the component. |
 | <span class="prop-name">SelectDisplayProps</span> | <span class="prop-type">object</span> |  | Props applied to the clickable div element. |
 | <span class="prop-name">value</span> | <span class="prop-type">any</span> |  | The input value. This prop is required when the `native` prop is `false` (default). |
-| <span class="prop-name">variant</span> | <span class="prop-type">'standard'<br>&#124;&nbsp;'outlined'<br>&#124;&nbsp;'filled'</span> |  | The variant to use. |
+| <span class="prop-name">variant</span> | <span class="prop-type">'standard'<br>&#124;&nbsp;'outlined'<br>&#124;&nbsp;'filled'</span> | <span class="prop-default">'standard'</span> | The variant to use. |
 
 The `ref` is forwarded to the root element.
 
diff --git a/docs/src/pages/components/selects/NativeSelects.js b/docs/src/pages/components/selects/NativeSelects.js
--- a/docs/src/pages/components/selects/NativeSelects.js
+++ b/docs/src/pages/components/selects/NativeSelects.js
@@ -1,8 +1,5 @@
 import React from 'react';
 import { makeStyles } from '@material-ui/core/styles';
-import Input from '@material-ui/core/Input';
-import OutlinedInput from '@material-ui/core/OutlinedInput';
-import FilledInput from '@material-ui/core/FilledInput';
 import InputLabel from '@material-ui/core/InputLabel';
 import FormHelperText from '@material-ui/core/FormHelperText';
 import FormControl from '@material-ui/core/FormControl';
@@ -67,7 +64,10 @@ export default function NativeSelects() {
         <NativeSelect
           value={state.age}
           onChange={handleChange('age')}
-          input={<Input name="age" id="age-native-helper" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-native-helper',
+          }}
         >
           <option value="" />
           <option value={10}>Ten</option>
@@ -98,7 +98,10 @@ export default function NativeSelects() {
         <NativeSelect
           value={state.age}
           onChange={handleChange('age')}
-          input={<Input name="age" id="age-native-label-placeholder" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-native-label-placeholder',
+          }}
         >
           <option value="">None</option>
           <option value={10}>Ten</option>
@@ -112,7 +115,10 @@ export default function NativeSelects() {
         <NativeSelect
           value={state.name}
           onChange={handleChange('name')}
-          input={<Input name="name" id="name-native-disabled" />}
+          inputProps={{
+            name: 'name',
+            id: 'name-native-disabled',
+          }}
         >
           <option value="" />
           <optgroup label="Author">
@@ -131,7 +137,9 @@ export default function NativeSelects() {
           value={state.name}
           onChange={handleChange('name')}
           name="name"
-          input={<Input id="name-native-error" />}
+          inputProps={{
+            id: 'name-native-error',
+          }}
         >
           <option value="" />
           <optgroup label="Author">
@@ -146,7 +154,13 @@ export default function NativeSelects() {
       </FormControl>
       <FormControl className={classes.formControl}>
         <InputLabel htmlFor="uncontrolled-native">Name</InputLabel>
-        <NativeSelect defaultValue={30} input={<Input name="name" id="uncontrolled-native" />}>
+        <NativeSelect
+          defaultValue={30}
+          inputProps={{
+            name: 'name',
+            id: 'uncontrolled-native',
+          }}
+        >
           <option value="" />
           <option value={10}>Ten</option>
           <option value={20}>Twenty</option>
@@ -197,9 +211,11 @@ export default function NativeSelects() {
           native
           value={state.age}
           onChange={handleChange('age')}
-          input={
-            <OutlinedInput name="age" labelWidth={labelWidth} id="outlined-age-native-simple" />
-          }
+          labelWidth={labelWidth}
+          inputProps={{
+            name: 'age',
+            id: 'outlined-age-native-simple',
+          }}
         >
           <option value="" />
           <option value={10}>Ten</option>
@@ -213,7 +229,10 @@ export default function NativeSelects() {
           native
           value={state.age}
           onChange={handleChange('age')}
-          input={<FilledInput name="age" id="filled-age-native-simple" />}
+          inputProps={{
+            name: 'age',
+            id: 'filled-age-native-simple',
+          }}
         >
           <option value="" />
           <option value={10}>Ten</option>
diff --git a/docs/src/pages/components/selects/NativeSelects.tsx b/docs/src/pages/components/selects/NativeSelects.tsx
--- a/docs/src/pages/components/selects/NativeSelects.tsx
+++ b/docs/src/pages/components/selects/NativeSelects.tsx
@@ -1,8 +1,5 @@
 import React from 'react';
 import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
-import Input from '@material-ui/core/Input';
-import OutlinedInput from '@material-ui/core/OutlinedInput';
-import FilledInput from '@material-ui/core/FilledInput';
 import InputLabel from '@material-ui/core/InputLabel';
 import FormHelperText from '@material-ui/core/FormHelperText';
 import FormControl from '@material-ui/core/FormControl';
@@ -71,7 +68,10 @@ export default function NativeSelects() {
         <NativeSelect
           value={state.age}
           onChange={handleChange('age')}
-          input={<Input name="age" id="age-native-helper" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-native-helper',
+          }}
         >
           <option value="" />
           <option value={10}>Ten</option>
@@ -102,7 +102,10 @@ export default function NativeSelects() {
         <NativeSelect
           value={state.age}
           onChange={handleChange('age')}
-          input={<Input name="age" id="age-native-label-placeholder" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-native-label-placeholder',
+          }}
         >
           <option value="">None</option>
           <option value={10}>Ten</option>
@@ -116,7 +119,10 @@ export default function NativeSelects() {
         <NativeSelect
           value={state.name}
           onChange={handleChange('name')}
-          input={<Input name="name" id="name-native-disabled" />}
+          inputProps={{
+            name: 'name',
+            id: 'name-native-disabled',
+          }}
         >
           <option value="" />
           <optgroup label="Author">
@@ -135,7 +141,9 @@ export default function NativeSelects() {
           value={state.name}
           onChange={handleChange('name')}
           name="name"
-          input={<Input id="name-native-error" />}
+          inputProps={{
+            id: 'name-native-error',
+          }}
         >
           <option value="" />
           <optgroup label="Author">
@@ -150,7 +158,13 @@ export default function NativeSelects() {
       </FormControl>
       <FormControl className={classes.formControl}>
         <InputLabel htmlFor="uncontrolled-native">Name</InputLabel>
-        <NativeSelect defaultValue={30} input={<Input name="name" id="uncontrolled-native" />}>
+        <NativeSelect
+          defaultValue={30}
+          inputProps={{
+            name: 'name',
+            id: 'uncontrolled-native',
+          }}
+        >
           <option value="" />
           <option value={10}>Ten</option>
           <option value={20}>Twenty</option>
@@ -201,9 +215,11 @@ export default function NativeSelects() {
           native
           value={state.age}
           onChange={handleChange('age')}
-          input={
-            <OutlinedInput name="age" labelWidth={labelWidth} id="outlined-age-native-simple" />
-          }
+          labelWidth={labelWidth}
+          inputProps={{
+            name: 'age',
+            id: 'outlined-age-native-simple',
+          }}
         >
           <option value="" />
           <option value={10}>Ten</option>
@@ -217,7 +233,10 @@ export default function NativeSelects() {
           native
           value={state.age}
           onChange={handleChange('age')}
-          input={<FilledInput name="age" id="filled-age-native-simple" />}
+          inputProps={{
+            name: 'age',
+            id: 'filled-age-native-simple',
+          }}
         >
           <option value="" />
           <option value={10}>Ten</option>
diff --git a/docs/src/pages/components/selects/SimpleSelect.js b/docs/src/pages/components/selects/SimpleSelect.js
--- a/docs/src/pages/components/selects/SimpleSelect.js
+++ b/docs/src/pages/components/selects/SimpleSelect.js
@@ -1,8 +1,5 @@
 import React from 'react';
 import { makeStyles } from '@material-ui/core/styles';
-import Input from '@material-ui/core/Input';
-import OutlinedInput from '@material-ui/core/OutlinedInput';
-import FilledInput from '@material-ui/core/FilledInput';
 import InputLabel from '@material-ui/core/InputLabel';
 import MenuItem from '@material-ui/core/MenuItem';
 import FormHelperText from '@material-ui/core/FormHelperText';
@@ -65,7 +62,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<Input name="age" id="age-helper" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-helper',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -100,7 +100,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<Input name="age" id="age-label-placeholder" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-label-placeholder',
+          }}
           displayEmpty
           name="age"
           className={classes.selectEmpty}
@@ -119,7 +122,10 @@ export default function SimpleSelect() {
         <Select
           value={values.name}
           onChange={handleChange}
-          input={<Input name="name" id="name-disabled" />}
+          inputProps={{
+            name: 'name',
+            id: 'name-disabled',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -137,7 +143,9 @@ export default function SimpleSelect() {
           onChange={handleChange}
           name="name"
           renderValue={value => `⚠️  - ${value}`}
-          input={<Input id="name-error" />}
+          inputProps={{
+            id: 'name-error',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -153,7 +161,11 @@ export default function SimpleSelect() {
         <Select
           value={values.name}
           onChange={handleChange}
-          input={<Input name="name" id="name-readonly" readOnly />}
+          inputProps={{
+            name: 'name',
+            id: 'name-readonly',
+            readOnly: true,
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -169,7 +181,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<Input name="age" id="age-auto-width" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-auto-width',
+          }}
           autoWidth
         >
           <MenuItem value="">
@@ -225,7 +240,11 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<OutlinedInput labelWidth={labelWidth} name="age" id="outlined-age-simple" />}
+          labelWidth={labelWidth}
+          inputProps={{
+            name: 'age',
+            id: 'outlined-age-simple',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -240,7 +259,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<FilledInput name="age" id="filled-age-simple" />}
+          inputProps={{
+            name: 'age',
+            id: 'filled-age-simple',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
diff --git a/docs/src/pages/components/selects/SimpleSelect.tsx b/docs/src/pages/components/selects/SimpleSelect.tsx
--- a/docs/src/pages/components/selects/SimpleSelect.tsx
+++ b/docs/src/pages/components/selects/SimpleSelect.tsx
@@ -1,8 +1,5 @@
 import React from 'react';
 import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
-import Input from '@material-ui/core/Input';
-import OutlinedInput from '@material-ui/core/OutlinedInput';
-import FilledInput from '@material-ui/core/FilledInput';
 import InputLabel from '@material-ui/core/InputLabel';
 import MenuItem from '@material-ui/core/MenuItem';
 import FormHelperText from '@material-ui/core/FormHelperText';
@@ -67,7 +64,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<Input name="age" id="age-helper" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-helper',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -102,7 +102,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<Input name="age" id="age-label-placeholder" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-label-placeholder',
+          }}
           displayEmpty
           name="age"
           className={classes.selectEmpty}
@@ -121,7 +124,10 @@ export default function SimpleSelect() {
         <Select
           value={values.name}
           onChange={handleChange}
-          input={<Input name="name" id="name-disabled" />}
+          inputProps={{
+            name: 'name',
+            id: 'name-disabled',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -139,7 +145,9 @@ export default function SimpleSelect() {
           onChange={handleChange}
           name="name"
           renderValue={value => `⚠️  - ${value}`}
-          input={<Input id="name-error" />}
+          inputProps={{
+            id: 'name-error',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -155,7 +163,11 @@ export default function SimpleSelect() {
         <Select
           value={values.name}
           onChange={handleChange}
-          input={<Input name="name" id="name-readonly" readOnly />}
+          inputProps={{
+            name: 'name',
+            id: 'name-readonly',
+            readOnly: true,
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -171,7 +183,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<Input name="age" id="age-auto-width" />}
+          inputProps={{
+            name: 'age',
+            id: 'age-auto-width',
+          }}
           autoWidth
         >
           <MenuItem value="">
@@ -227,7 +242,11 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<OutlinedInput labelWidth={labelWidth} name="age" id="outlined-age-simple" />}
+          labelWidth={labelWidth}
+          inputProps={{
+            name: 'age',
+            id: 'outlined-age-simple',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
@@ -242,7 +261,10 @@ export default function SimpleSelect() {
         <Select
           value={values.age}
           onChange={handleChange}
-          input={<FilledInput name="age" id="filled-age-simple" />}
+          inputProps={{
+            name: 'age',
+            id: 'filled-age-simple',
+          }}
         >
           <MenuItem value="">
             <em>None</em>
diff --git a/packages/material-ui/src/Select/Select.d.ts b/packages/material-ui/src/Select/Select.d.ts
--- a/packages/material-ui/src/Select/Select.d.ts
+++ b/packages/material-ui/src/Select/Select.d.ts
@@ -11,6 +11,7 @@ export interface SelectProps
   displayEmpty?: boolean;
   IconComponent?: React.ElementType;
   input?: React.ReactNode;
+  labelWidth?: number;
   MenuProps?: Partial<MenuProps>;
   multiple?: boolean;
   native?: boolean;
diff --git a/packages/material-ui/src/Select/Select.js b/packages/material-ui/src/Select/Select.js
--- a/packages/material-ui/src/Select/Select.js
+++ b/packages/material-ui/src/Select/Select.js
@@ -9,11 +9,11 @@ import ArrowDropDownIcon from '../internal/svg-icons/ArrowDropDown';
 import Input from '../Input';
 import { styles as nativeSelectStyles } from '../NativeSelect/NativeSelect';
 import NativeSelectInput from '../NativeSelect/NativeSelectInput';
+import FilledInput from '../FilledInput';
+import OutlinedInput from '../OutlinedInput';
 
 export const styles = nativeSelectStyles;
 
-const defaultInput = <Input />;
-
 const Select = React.forwardRef(function Select(props, ref) {
   const {
     autoWidth = false,
@@ -21,7 +21,7 @@ const Select = React.forwardRef(function Select(props, ref) {
     classes,
     displayEmpty = false,
     IconComponent = ArrowDropDownIcon,
-    input = defaultInput,
+    input,
     inputProps,
     MenuProps,
     multiple = false,
@@ -31,7 +31,8 @@ const Select = React.forwardRef(function Select(props, ref) {
     open,
     renderValue,
     SelectDisplayProps,
-    variant,
+    variant: variantProps = 'standard',
+    labelWidth = 0,
     ...other
   } = props;
 
@@ -44,7 +45,17 @@ const Select = React.forwardRef(function Select(props, ref) {
     states: ['variant'],
   });
 
-  return React.cloneElement(input, {
+  const variant = fcs.variant || variantProps;
+
+  const InputComponent =
+    input ||
+    {
+      standard: <Input />,
+      outlined: <OutlinedInput labelWidth={labelWidth} />,
+      filled: <FilledInput />,
+    }[variant];
+
+  return React.cloneElement(InputComponent, {
     // Most of the logic is implemented in `SelectInput`.
     // The `Select` component is a simple API wrapper to expose something better to play with.
     inputComponent,
@@ -52,7 +63,7 @@ const Select = React.forwardRef(function Select(props, ref) {
     inputProps: {
       children,
       IconComponent,
-      variant: fcs.variant,
+      variant,
       type: undefined, // We render a select. We can ignore the type provided by the `Input`.
       multiple,
       ...(native
@@ -120,6 +131,11 @@ Select.propTypes = {
    * When `native` is `true`, the attributes are applied on the `select` element.
    */
   inputProps: PropTypes.object,
+  /**
+   * The label width to be used on OutlinedInput.
+   * This prop is required when the `variant` prop is `outlined`.
+   */
+  labelWidth: PropTypes.number,
   /**
    * Props applied to the [`Menu`](/api/menu/) element.
    */


Test patch:
diff --git a/packages/material-ui/src/Select/Select.test.js b/packages/material-ui/src/Select/Select.test.js
--- a/packages/material-ui/src/Select/Select.test.js
+++ b/packages/material-ui/src/Select/Select.test.js
@@ -7,6 +7,8 @@ import MenuItem from '../MenuItem';
 import Input from '../Input';
 import Select from './Select';
 import { spy } from 'sinon';
+import OutlinedInput from '../OutlinedInput';
+import FilledInput from '../FilledInput';
 
 describe('<Select />', () => {
   let classes;
@@ -80,6 +82,31 @@ describe('<Select />', () => {
     });
   });
 
+  describe('prop: variant', () => {
+    it('Should render a OutlinedInput', () => {
+      const wrapper = mount(
+        <Select
+          value=""
+          variant="outlined"
+          inputProps={{ name: 'age', id: 'outlined-age-simple' }}
+        />,
+      );
+      expect(wrapper.find(OutlinedInput)).to.exist;
+      expect(wrapper.find(OutlinedInput).props()).to.have.property('labelWidth', 0);
+    });
+
+    it('Should render a FilledInput', () => {
+      const wrapper = mount(
+        <Select
+          value=""
+          variant="filled"
+          inputProps={{ name: 'age', id: 'outlined-age-simple' }}
+        />,
+      );
+      expect(wrapper.find(FilledInput)).to.exist;
+    });
+  });
+
   describe('prop: value', () => {
     it('should be able to use an object', () => {
       const value = {};