skip to content

Creating an autogrowing textarea with React and Typescript

/ 2 min read

In my 6 years career I almost never had to make an autogrowing textarea field like the ones we have in Jira or Linear (i.e. description fields) 👇

But recently, I had to make one. While there are already some posts about this, e.g. THIS post by Owen, I thought I’d post my solution, which covers a slightly different scenario.

So basically, I create a hook

export const useInputHeight = (name: string, value: string | undefined) => {
const setInputHeight = useCallback(() => {
const textarea: HTMLTextAreaElement | null = document.querySelector(name);
if (!textarea) return;
textarea.style.height = textarea.scrollHeight + "px";
}, [name]);
useEffect(() => {
setInputHeight();
}, [value, setInputHeight]);
return setInputHeight;
};

It returns a setInputHeight function that we call in our onChange function.

const setNameInputHeight = useInputHeight('textarea[name="email"]', emailValue);
// ...
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInputHeight();
// ... other functionality
};

Do you need a value argument? No, you don’t, but in my case, the value was being updated on the client, so I had to adjust the field height every time it updated without me triggering the onChange event.

If that’s not the case, simplify it to be

export const useInputHeight = (name: string) => {
const setInputHeight = () => {
const textarea: HTMLTextAreaElement | null = document.querySelector(name);
if (!textarea) return;
textarea.style.height = textarea.scrollHeight + "px";
};
return setInputHeight;
};

That’s all you’d need.

You may have also noticed that I’m not using useRef() and simply doing document.querySelector.

Would ref work? Yes, yes it should. The only reason I was using querySelector was because I was using a UI library and textarea there wasn’t allowing a ref prop. So I didn’t want to do all those workarounds, querySelector seemed like a great option.

Do feel free to use a ref if you’d like, after all, it IS a more ‘React way’ of doing things 😁👍