textarea { resize: none; } to remove the corner grabber, or resize: vertical to allow only taller and shorter. In Tailwind, use resize-none or resize-y. To make the field grow with its text instead, use field-sizing: content (Tailwind: [field-sizing:content]) with a max-height, plus a short JavaScript fallback that sets style.height to scrollHeight.Point any HTML form at one endpoint. 500 free submissions — no card, no time limit — and unlimited forms.
Create free accountThe copy-paste CSS fix: resize: none
Browsers draw a small diagonal grabber in the bottom-right corner of every textarea. Dragging it lets the user make the field bigger, which can push it out of your layout. One line turns it off:
textarea {
resize: none;
}The resize property takes a few values, so you can also keep the grabber and limit the direction:
none: no grabber, the user cannot resize.both: drag in any direction (the default for a textarea in most browsers).vertical: only taller or shorter.horizontal: only wider or narrower.blockandinline: the logical versions of vertical and horizontal. In a normal left-to-right page,blockis vertical; in vertical writing modes they swap.
textarea.notes { resize: vertical; }
textarea.wide { resize: horizontal; }
textarea.logical { resize: block; }Why the grabber shows (and why resize only works with overflow)
The grabber appears because the browser's default stylesheet gives textareas resize: both and overflow: auto. The resize property only applies when overflow is something other than visible. That is why it works on a textarea out of the box, but does nothing on a plain div:
/* Ignored: overflow is visible by default on a div */
.panel { resize: both; }
/* Works: overflow is not visible */
.panel {
resize: both;
overflow: auto;
}The same rule explains a common bug the other way round: if a CSS reset sets overflow: visible on a textarea, the grabber disappears even though you never set resize: none.
Better UX: resize: vertical with min and max height
Removing resize completely is often more than you need. The usual problem is that users drag the field sideways and break the layout. resize: vertical fixes that and still lets people make the box taller to see more of what they typed:
textarea {
width: 100%;
resize: vertical;
min-height: 6rem; /* can't shrink to a single line */
max-height: 24rem; /* can't grow past the screen */
}Accessibility note: people with low vision, large font settings or zoomed pages often enlarge a textarea to read and edit their message. WCAG asks that content still works when text is resized, and a fixed tiny box with resize: none makes long answers hard to review. Keep vertical resize unless you replace it with an auto-growing field (below).
rows and cols vs CSS height and width
The rows and cols attributes set the starting size in lines and characters. CSS height and width override them when both are present:
<!-- 4 lines tall, about 40 characters wide -->
<textarea name="message" rows="4" cols="40"></textarea>
<!-- CSS wins over rows/cols -->
<style>
textarea { width: 100%; height: 8rem; }
</style>A good pattern is to keep rows as a sensible default (it works even before your CSS loads) and use CSS for the width, usually width: 100%. Use min-height rather than height if the field can grow. To cap how much the user can type, use maxlength, not a small box.
Auto-grow with field-sizing: content
The cleanest answer to "textarea auto height in CSS" is the new field-sizing property. With field-sizing: content, the textarea sizes itself to its text: it starts small, grows line by line as the user types, and shrinks when they delete. No JavaScript:
textarea {
field-sizing: content;
min-height: 3lh; /* at least 3 lines */
max-height: 20lh; /* then scroll */
resize: none; /* the field sizes itself */
}Browser support: Chrome and Edge 123+ and Opera support it, and Safari added it in recent versions. Firefox does not support it yet at the time of writing, so check caniuse before relying on it alone. Browsers that don't know the property ignore it and show a normal textarea, so it is safe to add.
JavaScript fallback
For browsers without field-sizing, reset the height to auto on each input, then set it to the content height. The reset is what lets the field shrink again:
const autoGrow = (el) => {
el.style.height = 'auto';
el.style.height = el.scrollHeight + 'px';
};
if (!CSS.supports('field-sizing', 'content')) {
document.querySelectorAll('textarea[data-autogrow]').forEach((el) => {
el.style.overflowY = 'hidden';
el.addEventListener('input', () => autoGrow(el));
autoGrow(el);
});
}If you set a max-height, switch overflow-y back to auto once scrollHeight passes it, so users can still scroll long text.
Tailwind: resize-none, resize-y and field-sizing
Tailwind ships utilities for every resize value:
resize-none:resize: noneresize-y:resize: verticalresize-x:resize: horizontalresize:resize: both
<textarea name="message" rows="4"
class="w-full resize-y min-h-24 max-h-96"></textarea>For auto-grow, use an arbitrary property. Newer Tailwind versions also include field-sizing-content, but the arbitrary form works everywhere:
<textarea name="message"
class="w-full resize-none [field-sizing:content] min-h-20 max-h-80"></textarea>React: auto-grow with a ref
In React, run the same height reset whenever the value changes. A ref gives you the DOM node, and useLayoutEffect resizes it before paint so there is no flicker:
import { useLayoutEffect, useRef, useState } from "react";
export function AutoGrowTextarea() {
const [value, setValue] = useState("");
const ref = useRef<HTMLTextAreaElement>(null);
useLayoutEffect(() => {
const el = ref.current;
if (!el) return;
el.style.height = "auto";
el.style.height = el.scrollHeight + "px";
}, [value]);
return (
<textarea
ref={ref}
name="message"
rows={3}
value={value}
onChange={(e) => setValue(e.target.value)}
style={{ resize: "none", overflowY: "hidden" }}
/>
);
}If you only target browsers with field-sizing support, drop the effect and use className="[field-sizing:content]".
A complete message field you can paste
This form posts to splitforms, so the message arrives by email and in your dashboard without a backend:
<form action="https://splitforms.com/api/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<label for="message">Message</label>
<textarea id="message" name="message" rows="4" maxlength="2000" required></textarea>
<button type="submit">Send</button>
</form>
<style>
#message {
width: 100%;
resize: vertical;
field-sizing: content;
min-height: 4lh;
max-height: 20lh;
}
</style>Get a free access key to try it. Hiding other built-in controls? See how to remove number input arrows.
FAQ
How do I disable textarea resize?
Add textarea { resize: none; } to your CSS. The corner grabber disappears and users can no longer drag the field bigger or smaller. To allow only up and down resizing, use resize: vertical instead.
Why does resize: none not work on my element?
The resize property only applies to elements whose overflow is not visible. A textarea has overflow: auto by default, so it works there. On a div you must also set overflow: auto, hidden or scroll, otherwise the resize value is ignored.
What is the Tailwind class for textarea resize none?
Use resize-none. Tailwind also has resize-y (vertical only), resize-x (horizontal only) and resize (both directions). For an auto-growing field, add the arbitrary property [field-sizing:content].
How do I make a textarea grow with its content in CSS?
Use field-sizing: content. The textarea then grows as the user types and shrinks when text is removed. Add min-height and max-height to keep it in bounds. It works in Chrome and Edge 123+ and recent Safari; for other browsers, add a small JavaScript fallback that sets the height to scrollHeight on input.
Is it bad for accessibility to disable textarea resize?
It can be. Users with low vision or large text settings often enlarge a textarea to read and edit what they wrote. resize: vertical keeps that ability while stopping the field from breaking your layout sideways, so it is usually a better choice than resize: none.
References: MDN: resize and MDN: field-sizing.