ui icon indicating copy to clipboard operation
ui copied to clipboard

Auto-growing Textareas [feature request]

Open johurul-haque opened this issue 1 year ago • 4 comments

I found the Textarea component. It would be great if it had a prop to enable/disable auto-growing.

johurul-haque avatar Feb 27 '24 09:02 johurul-haque

I have created one. Autosize textarea

hsuanyi-chou avatar Feb 27 '24 12:02 hsuanyi-chou

I have created one. Autosize textarea

Hey @hsuanyi-chou thanks for putting this together! Just chiming in that I had an edge case in my app that's different from the examples on your site and I wanted to share what worked for me to make it look right:

I have a very long placeholder. But when the component rendered, its height per the Inspector was always 54px. Not 52 like the default for the minHeight prop, nor 58 like I was passing as minHeight to the textarea. Odd. Either way, it was clear minHeight wasn't being respected, at least on mount, and I needed to do something to force that first height calculation.

I have never felt like I fully understood refs, but theoretically, the useAutosizeTextArea() hook should fire first when the component renders and again once textAreaRef becomes not null, which I assumed would happen immediately, since the ref is set in the JSX. Sort of like a useEffect runs right after mount. But this appears to not be the case.

When the component renders, textAreaRef=null, and triggerAutoSize="", as console logged from the useAutosizeTextArea() hook's useEffect(). Clicking into the textarea does not change these values, in fact there is no further console log until either a) I type something, or b) I blur focus out of the textarea, at which point the height calculation runs and everything looks right from then on. I have other normal text input fields on the same page, and clicking into (then blurring from) them also triggers the ref to change, and the height to recalculate.

So clearly I needed to make something change its value on mount, because the component wasn't going to run the calculation on its own, perhaps because the ref gets set silently? Seems weird.

Here's what I did that worked:

I set triggerAutoSize's useState() to " " (with a space) to start. Then in the useAutosizeTextArea() hook's useEffect() I removed the if so setTriggerAutoSize will always run when the component mounts, and I made sure it would pass an empty string when value is undefined.

It appears that a post-mount change to triggerAutoSize will fire useAutosizeTextArea(), which will pick up on the newly-set textAreaRef, and set the initial height of the textarea to fit my multiline placeholder text!

An annoying behavior but an easy fix :) Cheers!

tatwater avatar Mar 07 '24 06:03 tatwater

@tatwater Hi, can you provide a minimal reproducible example? There's an offset in the useAutosizeTextArea. The 2px offset is because of the border of textarea.

hsuanyi-chou avatar Mar 07 '24 08:03 hsuanyi-chou

I have created one. Autosize textarea

Thanks a lot!🎉

YikaJ avatar Mar 21 '24 02:03 YikaJ

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.

shadcn avatar Jun 10 '24 23:06 shadcn

I have created one. Autosize textarea

Absolute legend.

AdamC03 avatar Jun 25 '24 08:06 AdamC03

Just as an aside if others are attempting to have the text area start out as a smaller or larger size, you can make a very simple adjustment. In your component file, adjust the <textarea /> to have a height of your choosing. Here's an example:

return (
      <textarea
        {...props}
        value={value}
        ref={textAreaRef}
        className={cn(
          "flex h-[42px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
          className,
        )}
        onChange={(e) => {
          setTriggerAutoSize(e.target.value);
          onChange?.(e);
        }}
      />
    )

Here I set the height to 42px. Then once the text is passed on the useEffect() , the proper height is given.

kerbersystems avatar Aug 27 '24 19:08 kerbersystems