react-textarea-autosize: TextArea is wrong size initially (off by a hair), then it adjusts as you type?

I have a <TextareaAutosize> used with react-hook-form, and when it starts out, the textarea is slightly smaller than it should be. When I type, it fixes. What should I do to fix this? Is it the font that is throwing it off, or my CSS or something?

Here is a gif.

2021-11-04 01 48 58

Here is a snippet of my code from a larger project:

import TextareaAutosize from 'react-textarea-autosize'
import styles from './index.module.css'
import { Controller } from 'react-hook-form'

export default function TextField({
  label,
  placeholder,
  type,
  value,
  inputId,
  control,
  prefix,
  name,
  minHeight,
  ...props
}) {
  return (
    <div className={styles.field}>
      <label className={styles.label}>{label}</label>
      <div className={styles.inputContainer}>
        <Controller
          name={name}
          control={control}
          render={({ field }) => (
            <TextareaAutosize {...field} minRows={minHeight} className={styles.input} placeholder={placeholder} />
          )}
        />
      </div>
    </div>
  )
}

And usage like this:

function Details() {
  const { handleSubmit, control } = useForm()

  const onSubmit = (data) => {
    console.log(data)
  }

  return (
    <form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
      <legend className={styles.legend}>Details</legend>
      <TextField minHeight={4} control={control} name="blurb" label="Blurb" placeholder="Love to learn and make!" />
      <div className={styles.actions}><button className={styles.button} type="submit">Save</button></div>
    </form>
  )
}

The CSS for the file is here:

.field {
  padding-bottom: 20px;
}

.label {
  opacity: 0.7;
  font-size: 14px;
}

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}

.image {
  width: 100px;
  height: 100px;
  background: #eee;
  margin-right: 20px;
}

.imageContainer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.removeUploadButton {
  display: flex;
  cursor: pointer;
}

.addButton {
  display: flex;
  cursor: pointer;
}

.removeButton {
  display: flex;
  left: -6px;
  cursor: pointer;
}

.inputContainer {
  display: flex;
  padding: 10px 20px;
  margin: 10px 0px;
  background: #eee;
  width: 100%;
  border-radius: 4px;
  font-size: 22px;
}

.input {
  flex: 1;
}

.input::placeholder, .inputPrefix {
  color: #aaa;
}

.legend {
  text-transform: uppercase;
  font-size: 22px;
  opacity: 0.7;
}

.imageContent {
  display: flex;
  align-items: center;
}

.button {
  cursor: pointer;
  padding: 10px 20px;
  color: white;
  background: #777;
  border-radius: 4px;
  text-align: center;
  width: 200px;
}

Any ideas?

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 3
  • Comments: 16 (3 by maintainers)

Most upvoted comments

17.02.2023 But still no solution, except SonOfCrypto’s solution. it is sad…

Have the same issue with @headlessui/react when putting the textarea inside a modal

thx @raduflp for the workaround 👍🏻

using it like this

const [isRerendered, setIsRerendered] = useState(false)
useLayoutEffect(() => setIsRerendered(true), [])
{isRerendered && <TextareaAutosize />}

@raduflp that is… somewhat helpful but I also believe that this might be a different issue than the issue reported originally here.

In this codesandbox, our useLayoutEffect that calls resizeTextarea is called when the rendered textarea is not yet attached to the DOM. I suspect that this is some kind of deferred mounting implemented in one of the components coming from the @headlessui/react.

My bet is that this code is related: https://github.com/tailwindlabs/headlessui/blob/3bc754516985db9fa094e364ff10be4de34a473b/packages/%40headlessui-react/src/components/portal/portal.tsx#L71-L96

It looks like doing exactly that - mounting to a different container and then attaching/detaching it manually from within an effect. The problem is that… effects are called from the bottom to the top so our effect gets called first and we can’t measure what the height should be when the textarea isn’t mounted in the DOM.

@Andarist could not reproduce it for simple scenarios, but was able to reproduce it with @headlessui/react Transition Inspecting the broken scenarios you can see that the textarea style doesn’t have a height set compared to the working scenarios. Hope that helps

https://codesandbox.io/s/clever-shtern-uw09l-uw09l

Please always try to share a repro case in a runnable form - either by providing a git repository to clone or a codesandbox. OSS maintainers usually can’t afford the time to set up the repro, even if exact steps are given.

Experiencing the same thing in our app, started happening recently. We haven’t changed any styles or markup on that page nor updated the library, so it’s either a browser change (happens in Chrome/FF/Safari though) or something new in React.