Repository: mui/material-ui (TypeScript)
Date: 2021-04-06 04:53:14+00:00
Task type: Bug Fix

Issue:
[TextareaAutosize] calculates size incorrectly in Firefox
When calcualting minumal height based on `rowsMin` prop, resulting textarea is smaller than in Chrome.
Additionally, when all rows are filled, width shrinks a bit.

- [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 😯
This is a gif from https://material-ui.com/components/textarea-autosize/
Left is Chrome 89.0.4389.90, right is Firefox 88.0b2
![1](https://user-images.githubusercontent.com/17963791/112324362-88bd6100-8cd4-11eb-984a-c11d097e494c.gif)

## Expected Behavior 🤔

Both parts of the gif should look same.

## Steps to Reproduce 🕹

Open https://material-ui.com/components/textarea-autosize/ in Firefox.

## Context 🔦

Documentation page use `rowsMin={3}`.
The difference is bigger with `rowsMin={2}`, and sadly this is the rows amount I need.




Issue discussion:
Ok, so I had a look. I could narrow down the origin to the padding. See this reproduction: https://codesandbox.io/s/material-demo-forked-251xl?file=/demo.tsx
```jsx
import React from "react";
import TextareaAutosize from "@material-ui/core/TextareaAutosize";

export default function MinHeightTextarea() {
  return (
    <TextareaAutosize
      style={{ padding: 10 }}
      aria-label="minimum height"
      rowsMin={3}
      placeholder="Minimum 3 rows"
    />
  );
}
```

It completely fails in Firefox 87:

<img width="232" alt="Screenshot 2021-03-29 at 00 36 20" src="https://user-images.githubusercontent.com/3165635/112770389-e16b6180-9026-11eb-95af-4545d886da62.png">

We can easily solve the issue with:

```diff
diff --git a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js
index 0c2aed67f6..26e808ae96 100644
--- a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js
+++ b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js
@@ -64,11 +64,11 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(props, ref)
       getStyleValue(computedStyle, 'border-top-width');

     // The height of the inner content
-    const innerHeight = inputShallow.scrollHeight - padding;
+    const innerHeight = inputShallow.scrollHeight;

     // Measure height of a textarea with a single row
     inputShallow.value = 'x';
-    const singleRowHeight = inputShallow.scrollHeight - padding;
+    const singleRowHeight = inputShallow.scrollHeight;

     // The height of the outer content
     let outerHeight = innerHeight;
@@ -173,7 +173,12 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(props, ref)
         readOnly
         ref={shadowRef}
         tabIndex={-1}
-        style={{ ...styles.shadow, ...style }}
+        style={{
+          ...styles.shadow,
+          ...style,
+          // Firefox doesn't take the padding into account when computing scrollHeight
+          padding: 0,
+        }}
       />
     </React.Fragment>
   );
diff --git a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js
index 032d08db5e..9e9691d38e 100644
--- a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js
+++ b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js
@@ -20,7 +20,11 @@ describe('<TextareaAutosize />', () => {
     function setLayout(
       input,
       shadow,
-      { getComputedStyle, scrollHeight, lineHeight: lineHeightArg },
+      {
+        getComputedStyle, // the style of the input
+        scrollHeight, // the scroll height on a single line
+        lineHeight: lineHeightArg, // the scroll height with the value
+      },
     ) {
       const lineHeight = typeof lineHeightArg === 'function' ? lineHeightArg : () => lineHeightArg;

@@ -130,14 +134,14 @@ describe('<TextareaAutosize />', () => {
       const shadow = container.querySelector('textarea[aria-hidden=true]');
       setLayout(input, shadow, {
         getComputedStyle: {
-          'box-sizing': 'content-box',
+          'box-sizing': 'border-box',
           'padding-top': `${padding}px`,
         },
         scrollHeight: 30,
         lineHeight: 15,
       });
       forceUpdate();
-      expect(input.style).to.have.property('height', `${30 - padding}px`);
+      expect(input.style).to.have.property('height', `${30 + padding}px`);
       expect(input.style).to.have.property('overflow', 'hidden');
     });
```

We already have a visual regression coverage for this but only in Chrome so 🤷‍♂️.

----

Regarding the light change of default width when overflow hidden is applied, I would propose, simply:

```diff
diff --git a/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx b/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx
index 2f13219cf6..5730769090 100644
--- a/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx
+++ b/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx
@@ -7,6 +7,7 @@ export default function MinHeightTextarea() {
       aria-label="minimum height"
       minRows={3}
       placeholder="Minimum 3 rows"
+      style={{ width: 200 }}
     />
   );
 }
```
Hi I'm new here, is this issue still open and needs to be fixed? 
@bhairavee23 Correct
> @bhairavee23 Correct
then should i take it up? I'll raise a PR...  I'll try the changes you have suggested above
@oliviertassinari It seems the overflow:hidden issue cannot be solved with just width:200, I fixed it by changing the overflow:hidden to overflow-x: hidden.

Solution patch:
diff --git a/docs/src/pages/components/textarea-autosize/EmptyTextarea.js b/docs/src/pages/components/textarea-autosize/EmptyTextarea.js
--- a/docs/src/pages/components/textarea-autosize/EmptyTextarea.js
+++ b/docs/src/pages/components/textarea-autosize/EmptyTextarea.js
@@ -2,5 +2,11 @@ import * as React from 'react';
 import TextareaAutosize from '@material-ui/core/TextareaAutosize';
 
 export default function EmptyTextarea() {
-  return <TextareaAutosize aria-label="empty textarea" placeholder="Empty" />;
+  return (
+    <TextareaAutosize
+      aria-label="empty textarea"
+      placeholder="Empty"
+      style={{ width: 200 }}
+    />
+  );
 }
diff --git a/docs/src/pages/components/textarea-autosize/EmptyTextarea.tsx b/docs/src/pages/components/textarea-autosize/EmptyTextarea.tsx
--- a/docs/src/pages/components/textarea-autosize/EmptyTextarea.tsx
+++ b/docs/src/pages/components/textarea-autosize/EmptyTextarea.tsx
@@ -2,5 +2,11 @@ import * as React from 'react';
 import TextareaAutosize from '@material-ui/core/TextareaAutosize';
 
 export default function EmptyTextarea() {
-  return <TextareaAutosize aria-label="empty textarea" placeholder="Empty" />;
+  return (
+    <TextareaAutosize
+      aria-label="empty textarea"
+      placeholder="Empty"
+      style={{ width: 200 }}
+    />
+  );
 }
diff --git a/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.js b/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.js
--- a/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.js
+++ b/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.js
@@ -9,6 +9,7 @@ export default function MaxHeightTextarea() {
       placeholder="Maximum 4 rows"
       defaultValue="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
           ut labore et dolore magna aliqua."
+      style={{ width: 200 }}
     />
   );
 }
diff --git a/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.tsx b/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.tsx
--- a/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.tsx
+++ b/docs/src/pages/components/textarea-autosize/MaxHeightTextarea.tsx
@@ -9,6 +9,7 @@ export default function MaxHeightTextarea() {
       placeholder="Maximum 4 rows"
       defaultValue="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
           ut labore et dolore magna aliqua."
+      style={{ width: 200 }}
     />
   );
 }
diff --git a/docs/src/pages/components/textarea-autosize/MinHeightTextarea.js b/docs/src/pages/components/textarea-autosize/MinHeightTextarea.js
--- a/docs/src/pages/components/textarea-autosize/MinHeightTextarea.js
+++ b/docs/src/pages/components/textarea-autosize/MinHeightTextarea.js
@@ -7,6 +7,7 @@ export default function MinHeightTextarea() {
       aria-label="minimum height"
       minRows={3}
       placeholder="Minimum 3 rows"
+      style={{ width: 200 }}
     />
   );
 }
diff --git a/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx b/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx
--- a/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx
+++ b/docs/src/pages/components/textarea-autosize/MinHeightTextarea.tsx
@@ -7,6 +7,7 @@ export default function MinHeightTextarea() {
       aria-label="minimum height"
       minRows={3}
       placeholder="Minimum 3 rows"
+      style={{ width: 200 }}
     />
   );
 }
diff --git a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js
--- a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js
+++ b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.js
@@ -64,11 +64,11 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(props, ref)
       getStyleValue(computedStyle, 'border-top-width');
 
     // The height of the inner content
-    const innerHeight = inputShallow.scrollHeight - padding;
+    const innerHeight = inputShallow.scrollHeight;
 
     // Measure height of a textarea with a single row
     inputShallow.value = 'x';
-    const singleRowHeight = inputShallow.scrollHeight - padding;
+    const singleRowHeight = inputShallow.scrollHeight;
 
     // The height of the outer content
     let outerHeight = innerHeight;
@@ -173,7 +173,11 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(props, ref)
         readOnly
         ref={shadowRef}
         tabIndex={-1}
-        style={{ ...styles.shadow, ...style }}
+        style={{
+          ...styles.shadow,
+          ...style,
+          padding: 0,
+        }}
       />
     </React.Fragment>
   );


Test patch:
diff --git a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js
--- a/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js
+++ b/packages/material-ui/src/TextareaAutosize/TextareaAutosize.test.js
@@ -130,14 +130,14 @@ describe('<TextareaAutosize />', () => {
       const shadow = container.querySelector('textarea[aria-hidden=true]');
       setLayout(input, shadow, {
         getComputedStyle: {
-          'box-sizing': 'content-box',
+          'box-sizing': 'border-box',
           'padding-top': `${padding}px`,
         },
         scrollHeight: 30,
         lineHeight: 15,
       });
       forceUpdate();
-      expect(input.style).to.have.property('height', `${30 - padding}px`);
+      expect(input.style).to.have.property('height', `${30 + padding}px`);
       expect(input.style).to.have.property('overflow', 'hidden');
     });