0
(0)

A textarea can hold multiple lines of text but usually has a fix height and also it can be resized manually by the user. But what about automatic resize of the textarea, based on it’s content and the maximum limit that we set up? In the example above you can observe that it starts up with a certain height and extends that height with each new line added, collapses the height with each new line removed. Also it stops expanding when the textarea reached the maximum limit.

The react component for this textarea will be called like this:

<AutoResizeTextarea defaultHeight={27} maxHeight={200} />

The defaultHeight represents the initial height of our text field and maxHeight represents the limit where the expansion of the height will stop.

This is the the AutoResizeTextarea component:

import React, { useRef } from 'react';
import './AutoResizeTextareaProps.css';

interface AutoResizeTextareaProps {
  defaultHeight: number;
  maxHeight?: number;
}

const AutoResizeTextarea =  ({defaultHeight, maxHeight = 150}:AutoResizeTextareaProps):JSX.Element => {
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
    
  const handleChange = () => {
    const textarea = textareaRef.current;
    
    if(textarea) {
      const computedStyle = getComputedStyle(textarea);
      const textareaVPadding = parseInt(computedStyle.paddingTop) + parseInt(computedStyle.paddingBottom);
      const contentHeight = textarea.scrollHeight - textareaVPadding ;
      
      if(textarea.scrollHeight - textareaVPadding <= maxHeight) {
        textarea.style.height=`${defaultHeight}px`;
        textarea.style.height = `${textarea.scrollHeight - textareaVPadding}px`;
      }
    }
  }
  
  return (
    <textarea  
    className="comments"
    ref={textareaRef}
    style={{ height: `${defaultHeight}px` }}
    onChange={handleChange}>
    </textarea>
  )
}

export default AutoResizeTextarea;

Also I added a CSS file(AutoResizeTextareaProps.css) for styling the textarea:

.comments {
  width: 400px;
  border: 2px solid #ccc;
  resize: none;
  font-size: 20px;
  color: gray;
  padding: 5px 10px;
}

You use it like this:

Let me explain

This document is a TSX document, so we have Typescript with React. Since we can have 2 props on this component, we need to create some type definitions for these props. We create an interface AutoResizeTextareaProps that has a mandatory defaultHeight field that must be a number and an optional maxHeight field that is also a number. Then we applied for the optional field a default value of 150, associated the props with the interface and the function return with a JSX.Element because that is what we are returning, a textarea tag wrapped in a JSX context.

The className is useful for us to style this element by it’s class name. The style attribute will add the defaultHeight’s value that we defined on the component. The onChange event will be triggered on keyboard events and onPaste events and will call the handleChange function that does all the resizing. We also need the ref(reference) attribute to be able to put some style on the textarea. Let’s take a look on the handleChange function:

We used here the useRef() react hook to be able to target and change values on our textarea element and also get a rerendering of the component each time. The main logic to get the real height of the textarea is to get the height of the content in this textarea.

In order to do that we need get the scrollable height of the content(scrollHeight), but to get it properly first we need to reset the height on it to the default height each time and only after that to take the scrollHeight of the content.

if(textarea.scrollHeight - textareaVPadding <= maxHeight) {
        textarea.style.height=`${defaultHeight}px`;
        textarea.style.height = `${textarea.scrollHeight - textareaVPadding}px`;
      }

We also need to check if the scroll height is lower or equal then the maxheight, to never expand bigger then the max limit. As you can see we subtracted the vertical padding of the textarea to get the correct scroll height of this element. To get the top and bottom padding of the textarea I used getComputedStyle method and I’ve stored it in a variable since I am using it twice. It is good to know that this method returns a value in pixels with the px unit added at the end, this value having the type string. That is why I used the parseInt method to convert it to numbers.

That’s about it !

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.