Auto-Growing Textareas with CSS field-sizing: content
Introduction
An auto-growing textarea gets taller as you type, instead of scrolling inside a fixed box. Comment boxes, chat inputs
and message fields all want one, and until recently every one of them needed JavaScript: listen for input, measure
scrollHeight, and set the height to match.
field-sizing: content does it in CSS. It tells a textarea to size itself to its text, the way most elements
already size to their content, so it grows as you type and shrinks when you delete. Like accent-color, it improves the browser's own
controls instead of replacing them with custom widgets.
Basic Usage
textarea {
field-sizing: content;
}The textarea is now exactly as tall as its text. It grows as you type and shrinks again when you delete. In practice you'll almost always add a minimum and a maximum as well, covered in Setting Limits.
The property has two values. fixed is the default: the textarea keeps the size the browser gives it, such as the
height from rows. content makes it size to its text instead.
The JavaScript It Replaces
// What auto-growing textareas have shipped until now
textarea.addEventListener("input", () => {
textarea.style.height = "auto"; // let it shrink first
textarea.style.height = `${textarea.scrollHeight}px`;
});It's only two lines, but each has a cost:
- A forced layout on every keystroke. Reading
scrollHeightstraight after changingheightmakes the browser recalculate the layout immediately, every time a key is pressed. - The page can jump. Setting
height: autobriefly collapses a tall textarea. Inside a scrolled page or panel, that can shift the scroll position while someone is typing. - It ignores the border.
scrollHeightcovers the content and padding but not the border, so withbox-sizing: border-boxthe box ends up slightly too short unless you add the border widths back. - It only runs on
input. Text set from code, such as a saved draft or a form reset, doesn't fire the event, so the box stays the wrong size until you call the function yourself.
field-sizing: content has none of these problems. The browser sizes the control during normal layout, the same way
it sizes a paragraph, so there's nothing to measure and nothing to keep in sync.
Setting Limits
Content sizing has no minimum or maximum of its own. An empty textarea is about one line tall, and a pasted page of
text makes it as tall as the page. Set both limits with min-block-size and max-block-size:
textarea {
field-sizing: content;
min-block-size: 3lh; /* at least three lines */
max-block-size: 12lh; /* then it scrolls */
}The lh unit is the element's line height, so 3lh means "three lines of text", whatever the font size. Past the
maximum, the textarea stops growing and scrolls inside, just as an ordinary one does.
rows and cols Stop Working
With field-sizing: content, the rows and cols attributes no longer affect the size at all. They don't set a
starting size or a limit. <textarea rows="3"> collapses to one line when it's empty, so use min-block-size for the
starting height instead.
Padding and Border with lh
With box-sizing: border-box, which most CSS resets set,
min-block-size includes the padding and border. 3lh then leaves a little less than three lines for the text. If the exact number of lines matters, add the padding and
border back:
textarea {
padding: 0.625rem;
border: 1px solid;
min-block-size: calc(3lh + 2 * 0.625rem + 2px);
}Placeholder Text
An empty textarea sizes to its placeholder. A long placeholder therefore makes the box tall before anyone has typed,
and it shrinks as soon as they start. Keep placeholders short, or let min-block-size set the empty size.
Try It Live
Both textareas have rows="3". Type past the edge of each: the left one uses field-sizing: content and grows, while
the right one is a plain textarea that keeps its size and scrolls. Untick min-block-size to see rows ignored,
and untick max-block-size to let the box grow without limit. Turn on resize: vertical, drag the handle,
then keep typing to see the dragged height stop the growth. The readout shows how many lines tall each textarea is,
and whether it's scrolling.
Auto-Growing Textareas with field-sizing
Type past the edge of two textareas to compare field-sizing: content with a fixed size, and toggle the min and max limits and resize to see how each changes the growth.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>field-sizing Playground</title> </head> <body> <main class="playground"> <header class="playground-header"> <h1>Auto-Growing Textareas with field-sizing</h1> <p>Both textareas have <code>rows="3"</code>. Type past the edge of each: the left one uses <code>field-sizing: content</code> and grows, the right one keeps its fixed size and scrolls. Untick the limits to see the textarea follow its text alone, and turn on <code>resize</code> to see a manual drag stop the growth.</p> </header> <p class="tip support-tip">Your browser doesn't support <code>field-sizing</code>, so the left textarea keeps its fixed size, just like the right one. It's supported in Chrome and Edge 123, Safari 26.2 and Firefox 152 or later.</p> <fieldset class="control-group"> <legend>Limits</legend> <label class="checkbox-field"> <input type="checkbox" id="min-toggle" checked> <code>min-block-size: 3lh</code> </label> <label class="checkbox-field"> <input type="checkbox" id="max-toggle" checked> <code>max-block-size: 8lh</code> </label> <label class="checkbox-field"> <input type="checkbox" id="resize-toggle"> <code>resize: vertical</code> (untick to clear a dragged size) </label> </fieldset> <section class="demo-area" id="demo" aria-label="Auto-growing and fixed textareas"> <div class="pair"> <div class="field"> <label for="auto-textarea"><code>field-sizing: content</code></label> <textarea id="auto-textarea" class="auto-size" rows="3">Keep typing. This box grows with its content and shrinks again when you delete it.</textarea> </div> <div class="field"> <label for="fixed-textarea">Default (<code>rows="3"</code>)</label> <textarea id="fixed-textarea" rows="3">Keep typing. This box keeps its size and scrolls instead.</textarea> </div> </div> </section> <output class="readout" id="readout" aria-live="polite"></output> </main> <script src="./index.js"></script> </body> </html>
Starting sandbox…
No console output yet.
Relationship to resize
textarea {
field-sizing: content;
resize: none; /* keep the size in the browser's hands */
}resize adds a handle that lets someone drag the box to a new size. Dragging sets an explicit height on the
element, and an explicit size always beats content sizing. After a drag, the textarea stops growing and shrinking in
that direction and keeps the height it was dragged to.
So the two don't combine well. If the box should always follow its content, use resize: none. If people need to
make it larger by hand, keep resize: vertical and accept that a drag fixes its height from then on.
Browser Support and Fallbacks
field-sizing became Baseline in June 2026, when Firefox 152 shipped it. It's supported in Chrome and Edge 123,
Safari 26.2 and Firefox 152. Older browsers ignore the property, and the textarea keeps its usual fixed size and
scrolls. That's exactly what the field did before, so adding it is safe.
If auto-growth matters in older browsers too, keep the old script as a fallback and run it only where the property isn't supported:
if (!CSS.supports("field-sizing", "content")) {
for (const textarea of document.querySelectorAll("textarea")) {
const fit = () => {
textarea.style.height = "auto";
textarea.style.height = `${textarea.scrollHeight}px`;
};
textarea.addEventListener("input", fit);
fit();
}
}In CSS, @supports (field-sizing: content) does the same job, for styles that only make sense when the textarea
grows.
Accessibility
Keep the rest of the form reachable. Without a maximum, a long message pushes the submit button below the fold,
which is especially awkward on a phone with the on-screen keyboard open. A max-block-size keeps the button in view.
Keep the empty box inviting. A one-line textarea looks like a single-line input, so people may not realise they
can write more. A min-block-size of two or three lines signals a longer answer and gives a larger target to tap.
Nothing to announce. Screen readers don't report a field's size, so growing and shrinking doesn't need an ARIA attribute or a live region.
Common Pitfalls
1. Expecting rows to Set a Starting Size
rows and cols are ignored once a control is content-sized. Use min-block-size: 3lh for the starting height.
2. Leaving Out a Maximum
A pasted wall of text makes the textarea as tall as the text, pushing everything after it down the page. Always pair
field-sizing: content with max-block-size.
3. A Fixed Height Somewhere Else
height, block-size or an inline style set by an old auto-grow script all override content sizing. Remove the old
script, or guard it as shown in Browser Support and Fallbacks, when you add the
property.
4. A Textarea That Shrinks Sideways
Content sizing applies in both directions. A textarea that isn't stretched by its container, such as one inside a
flex row or an inline layout, also narrows to its longest line. Give it a width, such as inline-size: 100%, if it
should fill its container.
Where Should You Use This?
- Comment, message and chat boxes, where the field should start small and grow with what's typed
- Any textarea currently wired to a
scrollHeightlistener just to grow: remove the listener and add a maximum - Feedback, bio and description fields in forms, where answers range from one line to several paragraphs
Leave it out where the layout depends on the textarea having a fixed size, such as a code editor or a form whose fields must line up in a grid.
Key Takeaway
field-sizing: content lets a textarea size to its text, replacing the scrollHeight script that auto-growing
textareas have needed for years. Pair it with min-block-size and max-block-size in lh units, since rows no
longer sets a size, and use resize: none if the box should always follow its text. It's Baseline, and older browsers
simply keep the fixed size they had before.
Changelog
- — Initial publication.
Share this tutorial
Spotted a mistake or something outdated in this tutorial? Suggest a correction.