post/
Nothing
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;
$element.style.height = "auto";
$element.style.height = `${$element.scrollHeight}px`;
$element.style.resize = "none";
}
};
React.useEffect(() => {
updateTextareaHeight();
}, [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.

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.
Lastly
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} />
Demo
Did it all mean nothing? Did you waste your time?