mui / base-ui

Base UI is a library of headless ("unstyled") React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
https://mui.com/base-ui/
MIT License
179 stars 34 forks source link

[TextareaAutosize] Unstable height when rendered in a Next.js RSC page #166

Open vladpaul09 opened 10 months ago

vladpaul09 commented 10 months ago

Steps to reproduce 🕹

Live example: https://codesandbox.io/p/sandbox/https-github-com-mui-material-ui-issues-38607-5h5ndr?file=%2Fsrc%2Fapp%2Fpage.tsx%3A22%2C1

Unstable height TextField multiline on nextjs app router when i reload the page. Same thing happens on page first load. For bug reproduction, i used material-ui-nextjs-ts from the example folder. Video below.

https://github.com/mui/material-ui/assets/57659794/a37ddb07-246a-478e-b360-73e6518836b9

Current behavior 😯

No response

Expected behavior 🤔

No response

Context 🔦

No response

Your environment 🌎

Expand System: OS: Windows 10 10.0.19044 Binaries: Node: 16.16.0 - C:\Program Files\nodejs\node.EXE Yarn: Not Found npm: 8.11.0 - C:\Program Files\nodejs\npm.CMD Browsers: Chrome: 116.0.5845.97 Edge: Spartan (44.19041.1266.0), Chromium (116.0.1938.54) npmPackages: @emotion/react: latest => 11.11.1 @emotion/styled: latest => 11.11.0 @mui/base: 5.0.0-beta.11 @mui/core-downloads-tracker: 5.14.5 @mui/icons-material: latest => 5.14.3 @mui/material: latest => 5.14.5 @mui/private-theming: 5.14.5 @mui/styled-engine: 5.13.2 @mui/system: 5.14.5 @mui/types: 7.2.4 @mui/utils: 5.14.5 @types/react: latest => 18.2.21 react: 18.x => 18.2.0 react-dom: 18.x => 18.2.0 typescript: latest => 5.1.6

Search keywords:

mj12albert commented 10 months ago

@vladpaul09 I can reproduce this – as a workaround for now, you can wrap the component with NoSsr to achieve the effect on load if the parent wasn't an RSC component/page, here's a working sandbox: https://codesandbox.io/p/sandbox/https-github-com-mui-material-ui-issues-38607-5h5ndr?file=%2Fsrc%2Fapp%2Fpage.tsx%3A22%2C1

For reference, here's how the TextareaAutosize looks on load in a normal sandbox (no Next.js, no RSC) https://codesandbox.io/s/textareaautosize-no-rsc-s5cs9c

michaldudak commented 10 months ago

We don't have access to the DOM node on the server (as it doesn't exist there), so it's impossible to measure its height. I can't really think of another fix than the workaround suggested by @mj12albert.

oliviertassinari commented 8 months ago

As far as I know, it's a regression from mui/material-ui#35862. In the reproduction, the field is empty, there is no content to sync the layout with after hydration, so it doesn't matter of it's client-side or server-side rendered, we can fully rely on CSS

Simple fix:

diff --git a/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx b/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
index 9f582765f6..b9a1b045d1 100644
--- a/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
+++ b/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
@@ -69,7 +69,7 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(
   const shadowRef = React.useRef<HTMLTextAreaElement>(null);
   const renders = React.useRef(0);
   const [state, setState] = React.useState<State>({
-    outerHeightStyle: 0,
+    outerHeightStyle: undefined,
   });

   const getUpdatedState = React.useCallback(() => {

To make the types passs is tricker, maybe:

diff --git a/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx b/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
index 9f582765f6..7786524b89 100644
--- a/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
+++ b/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx
@@ -10,9 +10,14 @@ import {
 } from '@mui/utils';
 import { TextareaAutosizeProps } from './TextareaAutosize.types';

+type InitialState = {
+  outerHeightStyle: undefined;
+  overflow?: boolean;
+};
+
 type State = {
   outerHeightStyle: number;
-  overflow?: boolean | undefined;
+  overflow?: boolean;
 };

 function getStyleValue(value: string) {
@@ -68,8 +73,8 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(
   const handleRef = useForkRef(forwardedRef, inputRef);
   const shadowRef = React.useRef<HTMLTextAreaElement>(null);
   const renders = React.useRef(0);
-  const [state, setState] = React.useState<State>({
-    outerHeightStyle: 0,
+  const [state, setState] = React.useState<InitialState | State>({
+    outerHeightStyle: undefined,
   });

   const getUpdatedState = React.useCallback(() => {
@@ -127,7 +132,7 @@ const TextareaAutosize = React.forwardRef(function TextareaAutosize(
     return { outerHeightStyle, overflow };
   }, [maxRows, minRows, props.placeholder]);

-  const updateState = (prevState: State, newState: State) => {
+  const updateState = (prevState: State | InitialState, newState: State) => {
     const { outerHeightStyle, overflow } = newState;
     // Need a large enough difference to update the height.
     // This prevents infinite rendering loop.

Before

https://github.com/mui/material-ui/assets/3165635/3b32168c-f61d-49d8-a620-09d79d2fd7d6

After

https://github.com/mui/material-ui/assets/3165635/4de5a168-468e-4609-8b7a-1e6032f0fad5

gitstart commented 8 months ago

@mj12albert @michaldudak @oliviertassinari we would like to pick this up

Joshbwr commented 5 months ago

Any update on this?

deowansajal commented 4 months ago

I'm also having the Unstable height when setting the TextField with multiline in nextjs 14. Are there any update. how could fix the isssue

michaldudak commented 3 months ago

Working on the Base UI components' API changes is our top priority at the moment. Since these changes may affect the internals of the components, we don't want to focus on fixing bugs as there's a risk that this work may be unnecessary. When we have a consistent new API across all the existing components, we'll resume accepting contributions and focus more on bug fixes.