In HTML, how do you give a <textarea> an initial value, and what do its rows and cols attributes actually control?
answer
- no value attribute anywhere on it
- the children are the default value
- raw text: tags inside are literal
- first newline after the tag disappears
- lines visible, characters wide — nothing more
basics
~20 sA textarea has no value attribute: its initial text is whatever sits between the opening and closing tags, and a newline right after the opening tag is dropped by the parser. The rows and cols attributes set the visible line count and average character width.
solid answer
~40 sUnlike `<input>`, `<textarea>` has no `value` attribute — its default value is its element content, so you write `<textarea name="bio">Hello</textarea>`. The content is parsed as raw text, so tags inside it are literal characters and you must escape anything that looks like a closing textarea tag; a single newline immediately after the opening tag is swallowed by the parser, which is why people indent the closing tag and get mystery leading whitespace. `rows` is the number of visible text lines (default 2) and `cols` is the visible width in average character widths (default 20); both are just the initial box size and CSS overrides them. Because it is a default value, a form reset restores that content, not whatever the user typed.
code
html · 4 lines<!-- The first newline after the tag is dropped; later whitespace is not -->
<label for="note">Note</label>
<textarea id="note" name="note" rows="4">
Starts with S, no leading blank line.</textarea>go deeper
Know that a textarea's starting text goes between the tags rather than in a value attribute, and that rows sets how many lines are visible. Say plainly that neither rows nor cols caps the amount of text.
Explain that the content is the default value in the same sense as an input's value attribute, describe the raw-text parsing rules, and be ready to name the stripped-first-newline behaviour when asked why a field starts with blank space.
Show that you think about the value crossing boundaries: escaping when templating user content into the element, CRLF normalisation on submission versus a single newline in the DOM, and why serialising the DOM does not capture what the user typed.
Be ready to set the house rule for multi-line input across a product — where a plain textarea suffices versus where a rich editor is justified, and what the richer control costs in accessibility, paste handling, and sanitisation on the way to storage.
## Content is the value `<input>` carries its default in a `value` attribute. `<textarea>` cannot: its value is multi-line text, and attribute values are a poor place for line breaks. So the element's *children* are the value: ```html <label for="bio">Short bio</label> <textarea id="bio" name="bio" rows="6" cols="40">Frontend engineer.</textarea> ``` This is the element's **default value** — the same role `value` plays on an input. It is what the control shows on load and what a form reset restores. Once the user types, the current value lives only in the DOM; the markup does not change. Serialising the DOM back to a string therefore does not capture what the user typed, which is a classic surprise when someone tries to "save the HTML". ## The parser rules that bite `<textarea>` is a *raw text* element (along with `<title>`). Two consequences: 1. **Markup inside is not markup.** A `<b>` tag written inside a textarea shows up as the literal characters `<b>`, not as bold text. Only character references such as `&` are decoded. 2. **The closing tag cannot appear in the content.** The first closing textarea tag ends the element. If your server templates user content into a textarea, that same string appearing in the content would terminate it early and let the rest be parsed as markup — so escape at least `<` and `&` when interpolating. And the rule everyone hits once: **a newline immediately after the opening tag is stripped** by the parser. That is why this is safe — ```html <textarea> Hello</textarea> ``` — it yields exactly `Hello`. But this is not: ```html <textarea> Hello </textarea> ``` Only the *first* newline is dropped; the two indent spaces, the trailing newline and any further whitespace are all part of the value. Pretty-printed templates are the usual source of a textarea that mysteriously starts with blank space. Put the content flush against the tags, or emit it from a template expression. ## rows and cols `rows` is the number of text lines visible without scrolling; the default is 2. `cols` is the visible width measured in average character widths; the default is 20. Both are *initial sizing* only — they impose no limit whatsoever on how much the user may type, and CSS `width`/`height` override them. So why set them? Because they render before any stylesheet applies, they give a sensible box if CSS fails, and `rows` is the honest way to express "this field expects about six lines" — a size hint the user reads as an expectation of how much to write. Setting `cols` on a fluid layout is usually pointless since a width rule will win. Limiting the *amount* of text is a separate concern handled by `maxlength`/`minlength`, not by `rows`/`cols`. ## wrap, and what actually gets submitted `wrap` has two values. The default, `wrap="soft"`, means the text wraps visually but is submitted exactly as typed — no line breaks are inserted. `wrap="hard"` inserts a real line break at each wrap point in the submitted value, and requires `cols` to be specified so the browser knows where the wraps fall. `hard` is rare and only makes sense for fixed-width output such as plain-text email bodies. One more normalisation to know: line breaks in the value read from the DOM are `\n`, but on submission the value is normalised to CRLF (`\r\n`) pairs. Code that counts characters client-side and server-side can disagree by one byte per line break because of this. ## Resizing and the other attributes Browsers make textareas user-resizable by default; that behaviour is controlled by CSS, not markup. The genuinely useful markup attributes beyond the above are `placeholder` (a hint, never a substitute for a label), `readonly` (submitted but not editable), `disabled` (not editable and *not* submitted), and `spellcheck`. Auto-growing a textarea as the user types has no markup solution and requires script.
- What is the difference between wrap="soft" and wrap="hard" on a textarea?`soft` is the default: the text wraps visually but is submitted exactly as the user typed it, with no inserted line breaks. `hard` makes the browser insert real line breaks at every visual wrap point in the submitted value, and it requires `cols` so the wrap column is defined. You would only want `hard` when the consumer expects fixed-width plain text, such as a plain-text email body.
- You render user-supplied text into a textarea from a server template. What must you escape, and why?At minimum `<` and `&`. A textarea is a raw text element, so the first closing textarea tag in the content ends the element — unescaped content containing that string would close the field early and let the remainder be parsed as markup. Escaping `<` prevents that, and escaping `&` stops character references in the user's text from being decoded into something else.
- A user's 500-character text is rejected by the server as 512 characters. What in the textarea's behaviour could explain the discrepancy?Line-break normalisation. The value you read in the DOM uses a single `\n` per line break, but the value the browser submits normalises breaks to CRLF, adding one byte per line. A twelve-line message therefore arrives twelve characters longer than a client-side count suggested. Count on the same normalisation on both sides, or set the limit with `maxlength`, which the browser enforces consistently against what the user sees.
saying these in an interview costs you the question
- Setting an initial value with a value attribute on textarea
- Thinking rows and cols limit how much can be typed
- Putting HTML tags inside a textarea and expecting them to render
- Blaming CSS for a leading blank line from template indentation
- Assuming the markup updates as the user types