Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

field-sizing: content - Auto-Growing Textareas With Zero JavaScript

C
Carlo Fontanos
· 2 min read

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.

C
Written by Carlo Fontanos

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.

Message sent!

Your details are only used to reply to you.

Keep reading