DEV Community

Cover image for Auto-size <TextArea/>
Facundo Botta
Facundo Botta

Posted on

Auto-size <TextArea/>

Hi! Recently, in one of my React projects, I had to use a textarea for my contact form, and this time I wasn't willing to accept its default behavior... So here I show you the solution I found to give our component the auto-sizing property.

1. So, first we have to create the basic TextArea component and set some styles for it:

import React from 'react';

const TextArea = () => {
  const styles = {
    width: '100%',
    height: '70px',
    padding: '10px',
    outline: 'none',
    resize: 'none',
    borderRadius: '5px',
    scrollbarWidth: 'none', // Firefox
    '-ms-overflow-style': 'none',
    '::-webkit-scrollbar': {
      width: '0px'
    }
  };

  return (
    <textarea
      style={styles}
    />
  );
};

export default TextArea;

Enter fullscreen mode Exit fullscreen mode

You can set more styles or pass them as props if you want to.

2. Now, to use it, we have to import it:

import TextArea from '../components/TextArea';
import React, { useRef } from 'react';

function YourParentComponent () {
  const textAreaRef = useRef(null);

  return (
    <TextArea
      ref={textAreaRef}
      placeHolder={'I'm a auto-size textarea'}
      minHeight={'100px'}
    />
  );
};
Enter fullscreen mode Exit fullscreen mode

You can set a placeholder or more options with props. To access the value of our TextArea, we have to use the useRef hook and then pass the ref to the component, so we have to modify it a little:

import React from 'react';

// Thanks to the react's function forwardRef()
// we can give a external ref to our component.

const TextArea = forwardRef(( {minHeight = '50px', placeHolder}, ref) => {
  const styles = {
    width: '100%',
    minHeight,
    padding: '10px',
    outline: 'none',
    resize: 'none',
    borderRadius: '5px',
    scrollbarWidth: 'none', // Firefox
    '-ms-overflow-style': 'none',
    '::-webkit-scrollbar': {
      width: '0px'
    }
  };

  return (
    <textarea
      ref={ref}
      style={styles}
      placeHolder={placeHolder}
    />
  );
});

export default TextArea;

Enter fullscreen mode Exit fullscreen mode

3. Now we can set the behavior of auto-sizing:

// This simple function sets the textarea's height to its scrollHeight value.

  const handleHeight = (e) => {
    e.target.style.height = minHeight;
    e.target.style.height = `${e.target.scrollHeight}px`;
  };

// So we just have to call this function when the textarea's value changes.

  return (
    <textarea
      ref={ref}
      style={styles}
      placeHolder={placeHolder}
      onChange={(e) => handleHeight(e)}
    />
Enter fullscreen mode Exit fullscreen mode

And that's it! Now our textarea is more user-friendly, in my opinion:

textarea component in action

In my case, I'm using it with a default value taken from the database. So, you have to set the defaultValue and add a useEffect() to set the height on the first render. So, finally, the TextArea component looks like this:


import React, { useEffect, forwardRef } from 'react';

const TextArea = forwardRef(({ minHeight = '50px', content = '', placeholder = '' }, ref) => {

  useEffect(() => {
    if (ref.current) {
      ref.current.style.height = `${ref.current.scrollHeight}px`;
    }
  }, [content, ref]);

  const handleHeight = (e) => {
    e.target.style.height = minHeight;
    e.target.style.height = `${e.target.scrollHeight}px`;
  };
  const styles = {
    width: '100%',
    height: '70px',
    padding: '10px',
    outline: 'none',
    resize: 'none',
    fontSize: '18px',
    borderRadius: '5px',
    minHeight: minHeight,
    scrollbarWidth: 'none', // Firefox
    '-ms-overflow-style': 'none',
    '::-webkit-scrollbar': {
      width: '0px'
    }
  };
  return (
    <textarea
      ref={ref}
      style={styles}
      defaultValue={content}
      placeholder={placeholder}
      onChange={(e) => handleHeight(e)}
    />
  );
});

export default TextArea;

Enter fullscreen mode Exit fullscreen mode

Only as an example, I'll show you how to retrieve the value, but you can set this value in a FormData object in your form's submit function, for instance.

// In your parent component.

const takeValue = () => {
    console.log(textAreaRef.current.value);
  };
takeValue();
Enter fullscreen mode Exit fullscreen mode

If you're working with JavaScript and not using React, you can apply the same logic as the handleHeight() function, and instead of using useRef(), you can take the textarea element by its id with getElementById('your_textarea_id').

I hope the post has been helpful for you, and feel free to ask me any questions or leave comments!

Top comments (0)