Repository: mui/material-ui (TypeScript)
Date: 2021-11-11 20:23:10+00:00
Task type: Bug Fix

Issue:
[FormControl] Required bool does not render correctly
<!-- Provide a general summary of the issue in the Title above -->

With the required being set for Textfield or Formcontroll, the rendering is different.

<!-- Checked checkbox should look like this: [x] -->

- [X] The issue is present in the latest release.
- [X] I have searched the [issues](https://github.com/mui-org/material-ui/issues) of this repository and believe that this is not a duplicate.

## Current Behavior 😯

Here's an example of FormControll
![image](https://user-images.githubusercontent.com/88312868/138294040-03766726-f59f-483f-80a2-56eb316d4d7f.png)

And here's an example of TextInput
![image](https://user-images.githubusercontent.com/88312868/138294569-a3c800b8-e0f6-49a2-af38-9f810ca410ed.png)


## Expected Behavior 🤔

Both should have enough empty space and look indentical!

## Steps to Reproduce 🕹

https://codesandbox.io/s/cocky-mclean-35mkm?file=/src/Demo.tsx

Steps:

1. Create FormControl
2. Create TextInput
3. Compare
4. Profit

## Context 🔦

Trying to make a registration page, and now two inputs look different :(

## Your Environment 🌎

<details>
  <summary>`npx @mui/envinfo`</summary>
  
```
  System:
    OS: macOS 11.6
  Binaries:
    Node: 14.17.5 - /usr/local/bin/node
    Yarn: 1.22.15 - /usr/local/bin/yarn
    npm: 7.21.1 - /usr/local/bin/npm
  Browsers:
    Chrome: Not Found
    Edge: Not Found
    Firefox: Not Found
    Safari: 15.0
  npmPackages:
    @emotion/react: ^11.4.1 => 11.4.1 
    @emotion/styled: ^11.3.0 => 11.3.0 
    @mui/core:  5.0.0-alpha.50 
    @mui/icons-material: ^5.0.3 => 5.0.3 
    @mui/lab: ^5.0.0-alpha.51 => 5.0.0-alpha.51 
    @mui/material: ^5.0.3 => 5.0.3 
    @mui/private-theming:  5.0.1 
    @mui/styled-engine:  5.0.1 
    @mui/system:  5.0.3 
    @mui/types:  7.0.0 
    @mui/utils:  5.0.1 
    @types/react: ^17.0.29 => 17.0.29 
    react: ^17.0.2 => 17.0.2 
    react-dom: ^17.0.2 => 17.0.2 
    typescript: ^4.4.4 => 4.4.4 
```
using Brave
</details>



Issue discussion:
@sbitenc, hi, this is because `InputLabel` does not have `Non-breaking space` in legend:

![image](https://user-images.githubusercontent.com/26045698/138873600-703f75c2-6d56-449d-abf2-dc0f35186405.png)

 but `TextField` have:
 
![image](https://user-images.githubusercontent.com/26045698/138874851-37f2a1dd-2f34-4642-a570-23bb9fb366d5.png)

A quick fix is ​​to remove line 143 in `TextField.js`
https://github.com/mui-org/material-ui/blob/b6cdaaf1a7f60de9ed66a491b7477fad19429905/packages/mui-material/src/TextField/TextField.js#L141-L144
@kirpinev I think setting label='Password*' works as well
@sbitenc  Empty space is still different.



> @sbitenc, hi, this is because `InputLabel` does not have `Non-breaking space` in legend:
> 
> ![image](https://user-images.githubusercontent.com/26045698/138873600-703f75c2-6d56-449d-abf2-dc0f35186405.png)
> 
> but `TextField` have:
> 
> ![image](https://user-images.githubusercontent.com/26045698/138874851-37f2a1dd-2f34-4642-a570-23bb9fb366d5.png)
> 
> A quick fix is ​​to remove line 143 in `TextField.js`
> 
> https://github.com/mui-org/material-ui/blob/b6cdaaf1a7f60de9ed66a491b7477fad19429905/packages/mui-material/src/TextField/TextField.js#L141-L144

I agree. Would you like to create a PR for this?
@hbjORbj sure
I don't think this is the correct solution. The Input's border touches the end of the label and it doesn't look right.

By removing the `{displayRequired && '\u00a0*'}` we're not keeping the hidden legend content consistent with the label.

In the case of FormControl with input, the InputLabel appends an asterisk, but the OutlinedInput does not. A better solution would be to make OutlinedInput also append it to its hidden legend, but I'm afraid this could be a breaking change (as is the previously proposed one).

A workaround, for now, would be to manually add `'\u00a0*'` to OutlinedInput's label when `required` is set.
Hi @michaldudak, May I work on this?
@alisasanib Of course, Michal would love you to.

Solution patch:
diff --git a/packages/mui-material/src/OutlinedInput/OutlinedInput.js b/packages/mui-material/src/OutlinedInput/OutlinedInput.js
--- a/packages/mui-material/src/OutlinedInput/OutlinedInput.js
+++ b/packages/mui-material/src/OutlinedInput/OutlinedInput.js
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
 import { refType } from '@mui/utils';
 import { unstable_composeClasses as composeClasses } from '@mui/base';
 import NotchedOutline from './NotchedOutline';
+import useFormControl from '../FormControl/useFormControl';
+import formControlState from '../FormControl/formControlState';
 import styled, { rootShouldForwardProp } from '../styles/styled';
 import outlinedInputClasses, { getOutlinedInputUtilityClass } from './outlinedInputClasses';
 import InputBase, {
@@ -124,13 +126,29 @@ const OutlinedInput = React.forwardRef(function OutlinedInput(inProps, ref) {
 
   const classes = useUtilityClasses(props);
 
+  const muiFormControl = useFormControl();
+  const fcs = formControlState({
+    props,
+    muiFormControl,
+    states: ['required'],
+  });
+
   return (
     <InputBase
       components={{ Root: OutlinedInputRoot, Input: OutlinedInputInput, ...components }}
       renderSuffix={(state) => (
         <NotchedOutlineRoot
           className={classes.notchedOutline}
-          label={label}
+          label={
+            label && fcs.required ? (
+              <React.Fragment>
+                {label}
+                &nbsp;{'*'}
+              </React.Fragment>
+            ) : (
+              label
+            )
+          }
           notched={
             typeof notched !== 'undefined'
               ? notched
diff --git a/packages/mui-material/src/TextField/TextField.js b/packages/mui-material/src/TextField/TextField.js
--- a/packages/mui-material/src/TextField/TextField.js
+++ b/packages/mui-material/src/TextField/TextField.js
@@ -135,15 +135,7 @@ const TextField = React.forwardRef(function TextField(inProps, ref) {
     if (InputLabelProps && typeof InputLabelProps.shrink !== 'undefined') {
       InputMore.notched = InputLabelProps.shrink;
     }
-    if (label) {
-      const displayRequired = InputLabelProps?.required ?? required;
-      InputMore.label = (
-        <React.Fragment>
-          {label}
-          {displayRequired && '\u00a0*'}
-        </React.Fragment>
-      );
-    }
+    InputMore.label = label;
   }
   if (select) {
     // unset defaults from textbox inputs


Test patch:
diff --git a/packages/mui-material/src/OutlinedInput/OutlinedInput.test.js b/packages/mui-material/src/OutlinedInput/OutlinedInput.test.js
--- a/packages/mui-material/src/OutlinedInput/OutlinedInput.test.js
+++ b/packages/mui-material/src/OutlinedInput/OutlinedInput.test.js
@@ -27,6 +27,18 @@ describe('<OutlinedInput />', () => {
     expect(container.querySelector('.notched-outlined')).not.to.equal(null);
   });
 
+  it('should set correct label prop on outline', () => {
+    const { container } = render(
+      <OutlinedInput
+        classes={{ notchedOutline: 'notched-outlined' }}
+        label={<div data-testid="label">label</div>}
+        required
+      />,
+    );
+    const notchOutlined = container.querySelector('.notched-outlined legend');
+    expect(notchOutlined).to.have.text('label\xa0*');
+  });
+
   it('should forward classes to InputBase', () => {
     render(<OutlinedInput error classes={{ error: 'error' }} />);
     expect(document.querySelector('.error')).not.to.equal(null);