Growing Textarea
Translated from German using DeepL.
Date: October 2025
Reading time: 2 minutes
Goal
An input field that automatically adjusts its height to fit the content.
Example:
Source: https://chat.com (opens in a new tab)
Problem
With the HTML elements and simple CSS styles available today, it is not possible to create a text field that automatically adjusts its height to the content.
Neither <input>
nor <textarea>
automatically increase in size vertically as the content increases.
Input
<input type="text" placeholder="Input"></input>
Textarea
Although the text area has a resize
functionality by default, this is not dynamic and must be controlled manually by the user.
In both cases, the height does not adjust automatically.
<textarea placeholder="Textarea"></textarea>
<textarea placeholder="Textarea" style={{resize:"none"}}></textarea>
Contenteditable
One possible solution is to use the contenteditable
attribute (contentEditable
in React).
This dynamically adjusts the size and is also used in ChatGPT, for example.
<span className="input" role="textbox" contentEditable></span>
ContentEditable
However, <input>
(single line) or <textarea>
(multiple lines) should always be used for user input.
This implementation has several disadvantages:
- Accessibility:
A
contenteditable
element is not a real form element. Support for screen readers and keyboard operation is limited.role=“textbox”
can help, but it is no substitute for a full A11y implementation. - Manual implementation of standard functions: Placeholders, validation, HTML filtering for copy/paste, etc. All of this must be implemented manually.
- Form behavior:
contenteditable
elements are not natively integrated into form behavior. Functions such as submitting on Enter or form serialization require additional logic. - Other pitfalls: Unexpected behavior can occur if you don't find out and address all the other issues.
Possible Solution
My preferred solution is a <textarea>
that uses JavaScript to adjust its height (target.style.height
) to the height of the actual content (target.scrollHeight
).
export function TextareaCustom() {
const maxHeight = 120;
const handleInput = (ev) => {
const target = ev.target;
target.style.height = 'auto';
if (target.scrollHeight > maxHeight) {
target.style.height = `${maxHeight}px`;
} else {
target.style.height = `${target.scrollHeight}px`;
}
};
// rows={1} -> initial rows
// resize:"none" -> no user drag
return (
<textarea
rows={1}
placeholder="Custom Textarea"
onInput={handleInput}
style={{width:"184px", resize:"none"}}
></textarea>
);
}