DEV Community

Gabriel Linassi
Gabriel Linassi

Posted on

How to build a dynamically resizable textarea?

Making a textarea dynamically resizable is fundamental to delivering a good UX on a text editor, a comment area or a get in a contact section. However, all the solutions available are too complex, require installing another dependency or need workarounds that are not a11y compliant.

In this post I'll show you a quick and simple solution for this problem using React, but you can apply it anywhere else.

Allright, show me the code then:

textarea {
  width: 500px;
  min-height: 100px;
  padding: 8px;
  font-size: 18px;
  resize: none;
  border: solid 1px;
  border-radius: 4px;
  outline: none;
}
Enter fullscreen mode Exit fullscreen mode
const ref = useRef<HTMLTextAreaElement>(null);

const handleInput = (e: ChangeEvent<HTMLTextAreaElement>) => {
  if (ref.current) {
    ref.current.style.height = "auto";
    ref.current.style.height = `${e.target.scrollHeight - 16}px`;
  }
};

return (
  <div className="App">
    <section>
      <textarea
        ref={ref}
        rows={1}
        placeholder="Enter text here..."
        onInput={handleInput}
      />
    </section>
  </div>
);
Enter fullscreen mode Exit fullscreen mode

Explanation

I want to call your attention to some key points. Notice we're setting the height to auto before setting it to scrollHeight-16. Forget the -16 for now, I'll talk about it later. Let's just leave the line below to explain how it works.

const handleInput = (e: ChangeEvent<HTMLTextAreaElement>) => {
  if (ref.current) {
    ref.current.style.height = `${e.target.scrollHeight}px`;
  }
};
Enter fullscreen mode Exit fullscreen mode

What happens is that on every keypress, the textarea will increase it's height. If you notice you'll see that the height is increasing by 16px on every keypres. That happens because the scrollHeight include padding. To exemplify, let's say the height of the textarea is 40px initially, then what happens on each keypres is this:

i) height = x+16
ii) height = x+16+16
iii) height = x+16+16+16
...
Enter fullscreen mode Exit fullscreen mode

That's why I subtracted the 16, because it's the sum of padding-top + padding-bottom and I don't to count it over again.

So by now the height should be resizing correctly when the size is increasing but if you delete a line you'll see that the height don't go shorter. To fix that, I set the height to auto before and it will do the job for us.

Also notice that I added the row={1}. That's because I don't want to have an empty line below the last line. Try to remove it to see how it will add extra space at the bottom of the textarea.

That's it, hope it helps. Thanks.

Sandbox

https://codesandbox.io/s/dynamically-resizable-textarea-9jbs1y

References:

i) https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas
ii) https://www.npmjs.com/package/autosize

Top comments (2)

Collapse
 
j471n profile image
Jatin Sharma

This is nice, i like this one 👍

Collapse
 
lelevan3010 profile image
Van Nguyen

Thanks! such a good simple solution