Textarea
The custom element is <hui-textarea>.
Overview
A form-associated multi-line text control. It submits through ElementInternals like hui-input, and the optional auto-resize keeps the field as tall as its content.
Example
Source
<hui-textarea name="notes" rows="4" placeholder="Notes" aria-label="Notes"></hui-textarea>The Go template that renders it:
<hui-textarea name="notes" rows="4" value="{{ .Notes }}" placeholder="Notes" aria-label="Notes"></hui-textarea>API
Attributes12
| Name | Type | Default | Description |
|---|---|---|---|
name | string | '' | The form field name. With no name the control contributes no entry to FormData. |
disabled | boolean | false | Disables the control and clears its form value. |
value | string | '' | The current value. Not reflected; the attribute only seeds the value restored by a form reset. |
placeholder | string | '' | Placeholder text, forwarded when non-empty. |
rows | number | 3 | The initial visible row count, forwarded to the native textarea. |
readonly | boolean | false | Makes the internal textarea read-only. |
required | boolean | false | Marks the control required and forwards constraint validity to the form. |
minlength | number | - | Minimum length, forwarded to the native textarea. Omitted when unset. |
maxlength | number | - | Maximum length, forwarded to the native textarea. Omitted when unset. |
autocomplete | string | - | An autocomplete hint, forwarded to the native textarea. Omitted when unset. |
auto-resize | boolean | false | Grows the textarea to its scroll height on every input. Reflected as auto-resize and exposed as the autoResize property. |
code | boolean | false | Draws the field as a code field: monospace, ligatures off, white-space: pre and a 2-column tab. Reflected. |
Properties14
| Name | Type | Default | Description |
|---|---|---|---|
name | string | '' | Reflects to the name attribute. |
disabled | boolean | false | Reflects to the disabled attribute. |
value | string | '' | The current value. Not reflected; changing it commits the new value to the form. |
placeholder | string | '' | Reflects to the placeholder attribute. |
rows | number | 3 | Reflects to the rows attribute. |
readonly | boolean | false | Reflects to the readonly attribute. |
required | boolean | false | Reflects to the required attribute. |
minlength | number | - | Reflects to the minlength attribute. |
maxlength | number | - | Reflects to the maxlength attribute. |
autocomplete | string | - | Reflects to the autocomplete attribute. |
autoResize | boolean | false | Reflects to the auto-resize attribute. |
code | boolean | false | Reflects to the code attribute. |
caret | { line: number; column: number } | - | Read-only. The caret's one-based line and column, normalised to \n and counting a tab as one character. |
selection | { start, end } | - | Read-only. Both ends of the selection, each a { line, column } position. |
Methods1
| Name | Type | Description |
|---|---|---|
selectRange(line, column, endLine?, endColumn?) | - | Moves the caret, and the selection, to a one-based line and column, focuses the control and scrolls it into view. Out-of-range input clamps to the nearest valid position rather than throwing. |
Events3
| Name | Description |
|---|---|
input | Emitted from the host on every keystroke, after the value, validity and auto-resize update. bubbles and composed; no detail. |
change | Emitted from the host when the native change fires. bubbles and composed; no detail. |
hui-caret-change | The caret moved - a keystroke, an arrow, a click or a selection. bubbles and composed, with detail { line, column }. |
CSS custom properties6
| Name | Default | Description |
|---|---|---|
--hui-background | oklch(1 0 0) | Field fill. |
--hui-input | oklch(0.62 0.019 323.02) | Border colour of the control boundary. |
--hui-font-mono | "JetBrains Mono", ui-monospace, … | Code-mode face; a host that sets it replaces the stack. |
--hui-radius | 0.45rem | Base radius; the field uses --hui-radius-lg. |
--hui-muted | oklch(0.96 0.003 325.6) | Fill while readonly. |
--hui-focus-ring-width | 3px | Width of the keyboard focus ring. |
::part() hooks2
| Name | Description |
|---|---|
input | The internal native <textarea>. |
control | The same element; the control carries both part names. |
States
Auto-resize
auto-resize grows the box with the text rather than scrolling it, starting at the height rows gives.
Source
<hui-textarea name="bio" rows="3" auto-resize value="one line" aria-label="Auto resize"></hui-textarea>Disabled
Disabled: greyed, out of the tab order, and not submitted.
Source
<hui-textarea name="locked" value="nope" disabled aria-label="Locked"></hui-textarea>Code mode
code draws the field as a code field: --hui-font-mono, ligatures off, white-space: pre and a 2-column tab. It is still a textarea, not an editor: a host that needs syntax highlighting mounts CodeMirror in a hui-field.
Source
<hui-textarea code rows="5" name="config" value="service: port: 8080 debug: true" aria-label="Configuration"></hui-textarea>Jump to a validation error
A server reports "line 2, column 9". The host renders the message and calls selectRange(2, 9), which moves the caret there and scrolls it into view; caret reads the position back. Lines and columns are one-based, and a tab counts as one character.
Source
<div style="display:flex;flex-direction:column;gap:.5rem;width:100%"> <hui-textarea code rows="3" name="config" aria-invalid="true" value="service: port: eight" aria-label="Configuration"></hui-textarea> <p class="hui-muted" style="margin:0">Line 2, column 9: port must be a number.</p></div>Server-side mechanics
The server owns name, value, rows, placeholder, required, minlength/maxlength, autocomplete, readonly, disabled and auto-resize, and the text submits under name through ElementInternals. As with hui-input, value is not reflected, so a swap has to re-render the value attribute to seed the control, and a swap mid-typing loses the unsaved text and focus. Server-side validation arrives as required and the length bounds, with aria-invalid="true" or a hui-field invalid wrapper supplying the invalid styling.
Accessibility
- The accessible name comes from an
aria-labelor from ahui-fieldlabel; IDREFs are resolved in the light DOM byhui-field. - The forwarded
aria-invalidswaps the border and focus ring to--hui-destructive. - Focus is shown with the shared ring on
:focus-visibleonly. auto-resizechanges only the visual height; it does not alter the control role or value.codechanges only the type and layout; validation,setCustomValidityand the submitted value are untouched.
Keyboard
| Keys | Action |
|---|---|
Tab, Shift+Tab | Moves focus to and from the control; Tab does not insert a tab character. |
Enter | Inserts a newline. |
Standard editing keys | Arrows, Home, End, Backspace and selection behave exactly as the native textarea does. |
Gotchas
valueis not reflected; the attribute only seeds the value restored by a form reset, so a server that reads it back sees the original.