Textarea
Accessible, unstyled native textarea with controlled and uncontrolled state.
| Package | @vizejs/ui/textarea |
| Maturity | stable |
| Own the source | vize lib pull textarea |
| Requires | controllable-state, id |
| Aliases | text area, multiline input, textarea field |
| Covers | HTML textarea, React Aria TextField, Reka UI Primitive |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { Textarea } from "@vizejs/ui/textarea";
Or copy the source into your project with vize lib pull textarea (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Labelled feedback textarea bound with v-model and a live character count. -->
<script setup lang="ts">
import { ref, useId } from "vue";
import { Textarea } from "@vizejs/ui/textarea";
const message = ref("");
const fieldId = useId();
const hintId = useId();
</script>
<template>
<div>
<label :for="fieldId">Feedback</label>
<Textarea
:id="fieldId"
v-model="message"
name="feedback"
:rows="4"
:maxlength="280"
placeholder="Tell us what you think"
:aria-describedby="hintId"
/>
<p :id="hintId">{{ message.length }} / 280 characters</p>
</div>
</template>
API
Textarea
Source: src/families/form/textarea/textarea-control.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Consumer-owned control id. null and undefined select a deterministic fallback. |
name |
string |
undefined |
Native form field name. |
modelValue |
string |
undefined |
Controlled string value. undefined selects uncontrolled behavior. |
defaultValue |
string |
"" |
Initial value for uncontrolled use and the value restored by form reset. |
disabled |
boolean |
false |
Disable editing, focus, and native form submission. |
readOnly |
boolean |
false |
Keep the textarea focusable while preventing user editing. |
required |
boolean |
false |
Mark the textarea as required for native constraint validation. |
placeholder |
string |
undefined |
Native placeholder text. |
autocomplete |
string |
undefined |
Native autocomplete hint. |
rows |
number |
undefined |
Suggested visible text row count. |
cols |
number |
undefined |
Suggested visible text column count. |
minlength |
number |
undefined |
Minimum accepted string length for native constraint validation. |
maxlength |
number |
undefined |
Maximum accepted string length for native constraint validation. |
spellcheck |
boolean |
undefined |
Native spellcheck preference. |
wrap |
TextareaWrap |
undefined |
Native line-wrapping policy. |
ariaLabel |
string |
undefined |
Accessible name when no label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the textarea. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the textarea. |
ariaErrormessage |
string |
undefined |
Id of the validation error message used while invalid. |
ariaInvalid |
TextareaAriaInvalid |
false |
Invalid state announced to assistive technology. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: string] |
Fired when the value requests a new controlled string. |
input |
[value: string, nativeEvent: Event] |
Fired after a native input event with the next string and native Event. |
change |
[value: string, nativeEvent: Event] |
Fired after native change/commit with the current string and native Event. |
compositionStart |
[value: string, nativeEvent: CompositionEvent] |
Fired when IME composition starts. |
compositionEnd |
[value: string, nativeEvent: CompositionEvent] |
Fired when IME composition ends. |
Exposed
| Member | Type | Description |
|---|---|---|
composing |
boolean |
Whether the native textarea is currently inside IME composition. |
value |
string |
Current controlled or uncontrolled string value. |
focus |
(options?: FocusOptions) => void |
Move focus to the native textarea. |
select |
() => void |
Select the current native textarea text. |
setSelectionRange |
( selectionStart: number, selectionEnd: number, direction?: "backward" | "forward" | "none", ) => void |
Set the native text selection range. |
setValue |
(value: string) => boolean |
Request a value update and report whether it differs. |
reset |
() => boolean |
Restore the current default value and report whether it changed. |
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
Behavior
Normative state × input → outcome table for textarea-control.vue (@vizejs/ui/textarea).
Every row is proven by the named mounted-DOM test in
src/families/form/textarea/textarea.test.ts; a
row without a passing test is a contract violation.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| T1 | editable, native | render | native <textarea>, deterministic id, accessible name, form attributes, line constraints, and invalid ARIA state |
renders a named native textarea with form and accessibility attributes |
| T2 | uncontrolled | native input / change | value follows the native element; emits update:modelValue before input, and emits change with the committed string |
uncontrolled textarea emits model before input and reports native change |
| T3 | controlled | native input | emits the request; the rendered value reverts to modelValue until the parent accepts the update |
controlled value wins until the parent accepts the request |
| T4 | uncontrolled, seeded | form reset | defaultValue seeds the initial value and form reset restores it without request-global state |
defaultValue seeds state and native form reset restores it |
| T5 | disabled | render / Tab | native disabled, data-state="disabled", no sequential focus |
disabled and read-only textareas keep native availability semantics |
| T6 | read-only | render / Tab | native readonly, data-state="readonly", remains focusable |
disabled and read-only textareas keep native availability semantics |
| T7 | composing | IME composition | data-composing and exposed composing track composition start/end while preserving the composed string |
tracks IME composition without losing the composed multiline value |
| T8 | uncontrolled | exposed methods | setValue() updates uncontrolled state, select() and setSelectionRange() update text selection, focus() focuses the field |
exposes value mutation, selection range, focus, and reset controls |
The subpath remains tree-shakable and retains no packaged CSS; those package
contracts are pinned by distribution.test.ts, check:size, and
check:tree-shaking.