field-sizing: content - Auto-Growing Textareas With Zero JavaScript
Textareas have been the wrong size since 1995: a fixed rows attribute, scrollbars for anything longer, and dead space for anything shorter. Every messaging UI ever built ships the same JavaScript - set height to auto, read scrollHeight, write it back, on every input event. The CSS replacement:
textarea.auto-grow {
field-sizing: content;
min-block-size: 3lh; /* start at three lines... */
max-block-size: 12lh; /* ...grow to twelve, then scroll */
}
field-sizing: content makes the control size itself to its contents, live, as the user types. The min/max constraints (in lh units - line-heights, the perfect unit for this job and itself a small hidden gem) give you the chat-app behavior exactly: comfortable start, sane ceiling, scrolling past it.
It's not just textareas
input.fit { field-sizing: content; min-inline-size: 8ch; }
select.fit { field-sizing: content; }
Text inputs grow horizontally with their value - inline-editing UIs (click a title, edit in place) stop needing width-measurement hacks with hidden spans. Selects shrink-wrap their selected option instead of reserving space for the longest one. Anywhere a control's fixed size fought its content, this is the answer.
The support situation, honestly
This is a Chromium feature for now: Chrome/Edge 123+. Firefox and Safari have it on their roadmaps but haven't shipped. That would disqualify layout-critical CSS - but auto-growing fields are pure enhancement, and the layered strategy is clean:
// Fallback only where CSS can't do it
if (!CSS.supports('field-sizing', 'content')) {
document.querySelectorAll('textarea.auto-grow').forEach((ta) => {
const grow = () => {
ta.style.height = 'auto';
ta.style.height = Math.min(ta.scrollHeight, 12 * lineHeight(ta)) + 'px';
};
ta.addEventListener('input', grow);
grow();
});
}
CSS.supports() (the JavaScript face of the @supports at-rule) gates the old JS to exactly the browsers that need it. Chromium users get the native version - which handles cases the JS classically fumbles: undo/redo, programmatic value changes, initial content on page load, pasted walls of text.
Details
- The rows/cols attributes stop affecting size under field-sizing: content - the min/max block-size constraints are your control surface.
- Layout-shift caution: fields that grow push content below them. In sticky-composer layouts (chat), anchor the composer and let the message list absorb the movement.
- Placeholder sizing: the field sizes to the placeholder when empty, which is usually what you want visually.
File this with scrollbar-gutter in the category of "a decade of fiddly JS becoming one declaration" - adopt it now, delete the fallback in a year or two.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.