Textarea
Stable Available in release assets
Present a native multiline text control while preserving browser-owned editing, validation, submission, scrolling, and resize behavior.
Textarea primary example
<div class="thin-field">
<label for="notes">Notes</label>
<textarea class="thin-textarea" id="notes" name="notes" rows="5" aria-describedby="notes-hint">
</textarea>
<small class="thin-hint" id="notes-hint">Add delivery details.</small>
</div>Show code
<div class="thin-field">
<label for="notes">Notes</label>
<textarea class="thin-textarea" id="notes" name="notes" rows="5" aria-describedby="notes-hint">
</textarea>
<small class="thin-hint" id="notes-hint">Add delivery details.</small>
</div>Variant gallery
Each authored example uses the production assets and includes copyable markup.
Default notes
A labelled native textarea keeps editing, resizing and submission browser-owned.
<form action="/notes" method="get" style="display: grid; gap: 1rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-default">Delivery notes</label>
<textarea class="thin-textarea" id="notes-default" name="notes" rows="3" >
</textarea>
</div>
<button class="thin-button">Save notes</button>
</form>Show code
<form action="/notes" method="get" style="display: grid; gap: 1rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-default">Delivery notes</label>
<textarea class="thin-textarea" id="notes-default" name="notes" rows="3" >
</textarea>
</div>
<button class="thin-button">Save notes</button>
</form>Required notes
Submit the empty form to exercise native required validation. No scripted validation is added.
<form action="/notes" method="get" style="display: grid; gap: 1rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-required">Required delivery notes</label>
<textarea class="thin-textarea" id="notes-required" name="notes" rows="3" required aria-describedby="notes-required-hint">
</textarea>
<small class="thin-hint" id="notes-required-hint">Describe where the parcel can be left.</small>
</div>
<button class="thin-button">Save notes</button>
</form>Show code
<form action="/notes" method="get" style="display: grid; gap: 1rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-required">Required delivery notes</label>
<textarea class="thin-textarea" id="notes-required" name="notes" rows="3" required aria-describedby="notes-required-hint">
</textarea>
<small class="thin-hint" id="notes-required-hint">Describe where the parcel can be left.</small>
</div>
<button class="thin-button">Save notes</button>
</form>Read-only record
The existing value can be selected and submitted but cannot be edited.
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-readonly">Recorded instructions</label>
<textarea class="thin-textarea" id="notes-readonly" name="notes" rows="3" readonly>Leave the parcel with reception.</textarea>
</div>Show code
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-readonly">Recorded instructions</label>
<textarea class="thin-textarea" id="notes-readonly" name="notes" rows="3" readonly>Leave the parcel with reception.</textarea>
</div>Disabled control
A native disabled textarea is excluded from focus order and form submission.
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-disabled">Notes unavailable</label>
<textarea class="thin-textarea" id="notes-disabled" name="notes" rows="3" disabled>Delivery has already completed.</textarea>
</div>Show code
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-disabled">Notes unavailable</label>
<textarea class="thin-textarea" id="notes-disabled" name="notes" rows="3" disabled>Delivery has already completed.</textarea>
</div>Authored eight-row editor
The rows attribute supplies the initial height; the theme maximum and native scrolling still apply.
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-rows">Long-form notes</label>
<textarea class="thin-textarea" id="notes-rows" name="notes" rows="8" >
</textarea>
</div>Show code
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-rows">Long-form notes</label>
<textarea class="thin-textarea" id="notes-rows" name="notes" rows="8" >
</textarea>
</div>Explicit autogrow opt-in
This example additionally imports /behaviors.js and calls enhanceAutogrowTextareas(). The textarea item itself only needs CSS. Without this optional script the authored rows and native resize remain useful.
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-autogrow">Growing notes</label>
<textarea class="thin-textarea" id="notes-autogrow" name="notes" rows="3" data-enhance="autogrow" aria-describedby="notes-autogrow-hint">
</textarea>
<small class="thin-hint" id="notes-autogrow-hint">Type several lines to grow this optional enhanced editor.</small>
</div>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Show code
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-autogrow">Growing notes</label>
<textarea class="thin-textarea" id="notes-autogrow" name="notes" rows="3" data-enhance="autogrow" aria-describedby="notes-autogrow-hint">
</textarea>
<small class="thin-hint" id="notes-autogrow-hint">Type several lines to grow this optional enhanced editor.</small>
</div>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Anatomy
- Explicitly associated label
- Native textarea.thin-textarea
- Native textarea child with authored name and rows
- Optional persistent hint
- Optional server or validation error
Variants and sizes
- Default — shown above
- Required — shown above
- Read-only — shown above
- Disabled — shown above
- Fixed authored rows — shown above
- Application opt-in autogrow enhancement — shown above
States and difficult content
Rendered fixtures exercise authored content and constrained layouts with the same production assets.
Empty and populated editors
Tab into either editor to inspect native focus. Values remain native form data.
<form action="/notes" method="get" style="display: grid; gap: 1rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-empty">Empty notes</label>
<textarea class="thin-textarea" id="notes-empty" name="notes" rows="3" >
</textarea>
</div>
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-filled">Existing notes</label>
<textarea class="thin-textarea" id="notes-filled" name="notes" rows="3" >Please ring the bell twice.</textarea>
</div>
<button class="thin-button">Save notes</button>
<thin-button data-variant="secondary">
<button type="reset">Reset notes</button>
</thin-button>
</form>Show code
<form action="/notes" method="get" style="display: grid; gap: 1rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-empty">Empty notes</label>
<textarea class="thin-textarea" id="notes-empty" name="notes" rows="3" >
</textarea>
</div>
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-filled">Existing notes</label>
<textarea class="thin-textarea" id="notes-filled" name="notes" rows="3" >Please ring the bell twice.</textarea>
</div>
<button class="thin-button">Save notes</button>
<thin-button data-variant="secondary">
<button type="reset">Reset notes</button>
</thin-button>
</form>Server-rendered invalid notes
The server owns aria-invalid and the persistent error. Correcting the value alone does not clear a server error; a subsequent response must update it.
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-invalid">Delivery instructions</label>
<textarea class="thin-textarea" id="notes-invalid" name="notes" rows="3" required aria-invalid="true" aria-describedby="notes-invalid-hint">
</textarea>
<small class="thin-hint" id="notes-invalid-hint">Enter delivery instructions before continuing.</small>
</div>Show code
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-invalid">Delivery instructions</label>
<textarea class="thin-textarea" id="notes-invalid" name="notes" rows="3" required aria-invalid="true" aria-describedby="notes-invalid-hint">
</textarea>
<small class="thin-hint" id="notes-invalid-hint">Enter delivery instructions before continuing.</small>
</div>Read-only and disabled records
Compare native selection and keyboard behavior. Read-only content remains available; disabled controls cannot be edited or submitted.
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-state-readonly">Recorded notes</label>
<textarea class="thin-textarea" id="notes-state-readonly" name="notes" rows="3" readonly>Collected at reception.</textarea>
</div>
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-state-disabled">Closed delivery</label>
<textarea class="thin-textarea" id="notes-state-disabled" name="notes" rows="3" disabled>No further changes.</textarea>
</div>Show code
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-state-readonly">Recorded notes</label>
<textarea class="thin-textarea" id="notes-state-readonly" name="notes" rows="3" readonly>Collected at reception.</textarea>
</div>
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-state-disabled">Closed delivery</label>
<textarea class="thin-textarea" id="notes-state-disabled" name="notes" rows="3" disabled>No further changes.</textarea>
</div>Narrow localized editor
Long text scrolls inside the native editor. Inspect at 200% and 400% browser zoom; automated checks separately exercise root text enlargement, which is not human zoom evidence.
<section lang="de" style="max-inline-size: 18rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-localized">Ausführliche Lieferhinweise für die internationale Zustellung</label>
<textarea class="thin-textarea" id="notes-localized" name="notes" rows="3" aria-describedby="notes-localized-hint">Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_</textarea>
<small class="thin-hint" id="notes-localized-hint">Bitte beschreiben Sie den gewünschten Ablageort und zusätzliche Hinweise für die Zustellung.</small>
</div>
</section>Show code
<section lang="de" style="max-inline-size: 18rem">
<div class="thin-field" style="overflow-wrap: anywhere">
<label for="notes-localized">Ausführliche Lieferhinweise für die internationale Zustellung</label>
<textarea class="thin-textarea" id="notes-localized" name="notes" rows="3" aria-describedby="notes-localized-hint">Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_Sendungsverfolgungsreferenz_</textarea>
<small class="thin-hint" id="notes-localized-hint">Bitte beschreiben Sie den gewünschten Ablageort und zusätzliche Hinweise für die Zustellung.</small>
</div>
</section>- Empty — shown above
- Populated — shown above
- Focused — shown above
- Invalid — shown above
- Disabled — shown above
- Read-only — shown above
- Long unbroken content — shown above
- Long localized label and hint — shown above
- Narrow container — shown above
- 200% and 400% zoom — shown above
Interaction and keyboard behavior
Typing, selection, clipboard commands, undo, scrolling, native constraint validation, form reset, value submission, and user-initiated vertical resizing remain browser owned.
Accessibility
Use an explicit label, retain visible focus, and connect persistent hints and errors with aria-describedby. Do not replace the textarea with contenteditable, suppress native resizing without an equivalent need, or use placeholder text as its accessible name.
- Contract
NATIVE- Basis
- Native <input>, <select>, and <textarea>; no APG widget
- Evidence
tests/unit/library/form-controls-stable.test.ts
API
Use <thin-textarea><textarea …></thin-textarea> with an authored name and rows. Native required, minlength, maxlength, readonly, disabled, autocomplete, wrap, and aria-describedby attributes remain the state and submission API.
Behavior tier: native
Structured host, property, and example tables are not authored for this item yet. Use the summary above and the primary example.
Fallback
The native textarea remains resizable, validated, and submitted without CSS or JavaScript.
Assets and dependencies
/components.css
Dependencies: None
Source: packages/ui/src/items/textarea/style.ts
Stability evidence
- Native value, validation, resize, and no-JavaScript contract:
test:tests/unit/library/form-inputs.test.ts - Complete item-specific API, fallback, and difficult-state documentation:
test:tests/unit/release/release-readiness.test.ts - Cross-theme, density, localized, narrow-container, zoom, and forced-colors fixture:
review:site/src/pages/quality/index.astro#quality-review
Composition
Derived from the examples and style specs, not authored.