Text Areas (<textarea>)
<textarea> is a multi-line text input — the right choice whenever users need to enter more than a single line, such as a comment, a message, or a bio. Unlike <input>, it's not a void element: its default text goes between the opening and closing tags, not in a value attribute.
basic-textarea.html
<label for="message">Your message</label> <textarea id="message" name="message"> Feel free to include as much detail as helpful. </textarea>
<textarea> has no value attribute for setting its initial content. Whatever text sits between <textarea> and </textarea> becomes the starting value — including any accidental whitespace or line breaks from your indentation, so be careful with formatting.rows and cols vs CSS Sizing
rows and cols set the textarea's initial visible size in terms of text rows and character-width columns. They're a rough, font-dependent way to size the box and were the only sizing option before CSS existed. Today, CSS width and height give far more precise, responsive control, and are generally preferred.
rows-cols.html
<textarea name="bio" rows="6" cols="40"></textarea>
css-sizing.css
textarea.bio {
width: 100%;
max-width: 480px;
height: 160px;
}Approach | Precision | Responsiveness |
|---|---|---|
| Approximate — depends on the rendered font | Fixed size regardless of viewport |
CSS | Exact pixel or relative-unit control | Can adapt with percentages, |
rows/cols attributes as a baseline — they apply immediately, before any stylesheet loads, avoiding a layout flash on slow connections.Controlling Resize with CSS
Most browsers let users drag a corner handle to resize a <textarea> by default. The resize CSS property controls whether that's allowed, and in which directions.
resize.css
/* Disable manual resizing entirely */
textarea.fixed-size {
resize: none;
}
/* Only allow vertical resizing, not horizontal */
textarea.comment-box {
resize: vertical;
}Value | Effect |
|---|---|
| User cannot resize the textarea at all |
| Default in most browsers — user can drag both dimensions |
| User can only change height |
| User can only change width |
Limiting Length with maxlength
The maxlength attribute caps how many characters the user can type, enforced natively by the browser as they type (not just on submit).
maxlength.html
<label for="tweet">What's happening?</label> <textarea id="tweet" name="tweet" maxlength="280" rows="4"></textarea>
maxlength silently stops accepting input once the limit is hit — that can confuse users who don't notice why typing stopped working. Pair it with a small JavaScript-driven counter (e.g. "42 / 280") so the limit is visible as they type.placeholder for Hint Text
placeholder shows light, temporary hint text inside the box until the user types something — useful for showing an example format, but it disappears on input and isn't read by all assistive technology the same way a real label is, so it should never replace a <label>.
placeholder.html
<label for="feedback">Feedback</label> <textarea id="feedback" name="feedback" placeholder="Tell us what worked well and what didn't..." rows="5" ></textarea>
Use
<textarea>for any multi-line free-text input, such as comments or messages.Its default content sits between the opening and closing tags — there is no
valueattribute.Prefer CSS width/height for precise, responsive sizing over relying solely on rows/cols.
Use the
resizeCSS property to allow, restrict, or disable manual resizing.maxlengthenforces a character cap live as the user types — pair it with a visible counter.placeholderis hint text, not a replacement for a real, persistent<label>.
Building a Live Character Counter
Combining maxlength with a small script that listens for the input event gives users real-time feedback on how much room they have left.
counter-markup.html
<label for="tweet">What's happening?</label> <textarea id="tweet" name="tweet" maxlength="280" rows="4"></textarea> <p><span id="count">0</span> / 280</p>
counter.js
const textarea = document.getElementById('tweet');
const counter = document.getElementById('count');
textarea.addEventListener('input', () => {
counter.textContent = textarea.value.length;
});Auto-Growing a Textarea to Fit Content
A textarea's height doesn't grow automatically as the user types more lines — it just scrolls internally once content exceeds the visible area. A common enhancement resets the height on each keystroke and sets it to match the content's actual scroll height.
auto-grow.js
const textarea = document.getElementById('message');
textarea.addEventListener('input', () => {
textarea.style.height = 'auto';
textarea.style.height = `${textarea.scrollHeight}px`;
});field-sizing: content in CSS, which auto-grows a <textarea> without any JavaScript. Support is still uneven across browsers, so the JavaScript approach above remains the more broadly compatible fallback.Read-Only and Disabled Textareas
Like other form controls, a <textarea> can be marked readonly (visible, submitted, but not editable) or disabled (not editable and not included in the form submission at all).
readonly-disabled.html
<label for="terms">Terms (read-only)</label> <textarea id="terms" readonly>These terms cannot be edited but are still submitted.</textarea> <label for="notes">Notes (disabled)</label> <textarea id="notes" disabled>This value will not be submitted at all.</textarea>
Spellcheck and Wrap Attributes
Attribute | Purpose |
|---|---|
| Set to |
|
|
spellcheck-wrap.html
<textarea name="snippet" spellcheck="false" wrap="hard" rows="6"></textarea>
wrap="hard" — otherwise the server may receive one unbroken line of text.