September 1, 20212 min read

React, TypeScript, Headless Component

It's really fun building a component specially if it works the way I want it to.

TL;DR, here's my take on a <TextArea> component in TypeScript:

import React from "react";

const Textarea = (props: React.TextareaHTMLAttributes<HTMLTextAreaElement>) => {
  const { value } = props;
  const textareaElement = React.useRef<HTMLTextAreaElement>(null);

  const updateTextareaHeight = () => {
    if (textareaElement.current) {
      const $element = textareaElement.current;

      $ = "auto";
      $ = `${$element.scrollHeight}px`;
      $ = "none";

  React.useEffect(() => {
  }, [value]);

  return <textarea ref={textareaElement} {...props} />;

export default Textarea;

Alright. Nothing more. Everything is very self explanatory. Who reads a blog post anyway? bye.

Just kidding.

A kitten saying hehe.

I've actually did quite a research on how to make a textarea component in React with TypeScript and I was not able to find an approach that is short and simple.

So here's how I made a headless auto-growing textarea component.

The props

First, I made sure that the <TextArea> component I defined will only accept the properties of a <textarea> element. This can be done assigning TextareaHTMLAttributes<HTMLTextAreaElement> to props.

The reference

Next, I need to define a reference to access and update the <textarea> element. To achieve this, I used the handy useRef() hook defaulting the value to null.

The effect

Now that I have the reference to the <textarea> element, I then use the useEffect() hook to call for updateTextareaHeight() whenever the value prop changes.

The updateTextareaHeight() handler will update the <textarea> element's height to auto and then set the height to the scrollHeight. This will make the <textarea> element grow as the user types.

The element

Lastly, I return the <textarea> with the ref attribute set to the textareaElement reference, passing all the props with the spread operator.


This is a headless component so feel free to apply styles that will suit your needs.

e.g. usage

<TextArea className="my-textarea-base-style rounded-lg" rows={1} />


Did it all mean nothing? Did you waste your time?

My Spotify is currently offline.