Skip to main content

Textarea

Info:Form html svelte astro Success: coverage 17/17

A multi-line text input: styled, labelled, and resizable, in three sizes with an invalid state.

Live demo

live · @xoji/astro

Textarea

A composed message

Sizes

Resize & states

Tell us a little more — at least 20 characters.

Textarea is a styled multi-line text control. It renders a native <textarea> that inherits the shared .xoji-control chrome, wrapped with an optional label and an error message slot.

The rows attribute sets the initial visible height and resize controls the user's drag handle (vertical by default, or none / horizontal / both). It exposes the same invalid / disabled / required and sm / md / lg size surface as the rest of the form family, and the custom element is form-associated so its value participates in native form submission and reset.

When to use

How this component composes with the rest of the set.

Pair with Button (type="submit" / type="reset") inside a <form>; the form-associated element submits and resets natively.
Mirror the label / invalid / error surface of Field and Select so a form reads consistently across single-line and multi-line inputs.

Props

11 props, straight from the manifest.

PropTypeDefaultBindingsDescription
label string
html svelte astro
The visible field label. When empty, the binding falls back to `aria-label` and warns if neither is set.
value string
html svelte astro
The textarea's text content. Two-way bindable in Svelte.
rows number 3
html svelte astro
Initial visible height of the control, in text rows.
resize TextareaResize
none vertical horizontal both
vertical
html svelte astro
Which axes the user can drag to resize the control.
placeholder string
html svelte astro
Placeholder text shown while the control is empty.
size Size
sm md lg
md
html svelte astro
Control size.
name string
html svelte astro
Form field name; submitted with the control's value.
disabled boolean false
html svelte astro
Disables interaction and excludes the value from form submission.
invalid boolean false
html svelte astro
Marks the control invalid: danger border and `aria-invalid`.
required boolean false
html svelte astro
Marks the field required; reflected as `aria-required` on the control.
error string
html svelte astro
Validation message rendered beneath the control and wired up via `aria-describedby` while invalid.

Appearance

Variants

default

.xoji-textarea

The standard control, neutral field chrome from .xoji-control.

invalid

.xoji-textarea--invalid

Error treatment: danger-colored border, label, and focus ring.

Sizes

sm

.xoji-textarea--sm

Compact.

md

default
.xoji-textarea

Default.

lg

.xoji-textarea--lg

Large.

States

focus-visible

.xoji-textarea__control:focus-visible

Keyboard focus: the shared .xoji-control ring, recolored to danger while invalid.

invalid

.xoji-textarea--invalid .xoji-textarea__control

Failing validation: danger border on the control and a danger label.

disabled

.xoji-textarea__control:disabled

Non-interactive: muted chrome inherited from .xoji-control, no-drop cursor.

Anatomy

The named parts that make up the component, with their selectors.

root

.xoji-textarea

The wrapper carrying the size, invalid, and resize classes; lays out label, control, and error.

--space-1 --font-sans

label

.xoji-textarea__label

The field label, hidden when no label text is provided.

--text-sm --weight-medium --fg-1 --leading-normal

control

.xoji-textarea__control

The native <textarea> inheriting .xoji-control, with size, resize, and min-height applied.

--space-7 --leading-normal

error

.xoji-textarea__error

The validation message shown beneath the control while invalid.

--text-sm --leading-normal --danger

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 17/17 consumed tokens produced default register: 276 tokens

Live coverage check against the xoji-default register (derive(xojiDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--border-normal --danger --danger-bg --danger-text --fg-1 --font-sans --leading-normal --space-1 --space-2 --space-3 --space-4 --space-6 --space-7 --space-8 --text-lg --text-sm --weight-medium

Slots

default
html astro

Initial textarea content, projected into the native control's value.

Accessibility

Renders a native <textarea>, so editing, selection, and screen-reader semantics come for free.
The label is wired to the control via for / id; with no label, the binding falls back to aria-label and warns when neither is present.
invalid sets aria-invalid="true"; when an error is present it is linked through aria-describedby.
required is reflected as aria-required on the control.
Focus is shown with the shared control ring plus a transparent outline that the forced-colors base rule promotes to a real system outline.

Code

Labelled, resizable, and invalid

A labelled control with custom rows, a fixed-height variant, and an invalid state with an error message.

<xoji-textarea label="Bio" name="bio" rows="4" placeholder="Tell us about yourself…"></xoji-textarea>

<xoji-textarea label="Notes" rows="6" resize="none"></xoji-textarea>

<xoji-textarea
	label="Summary"
	size="lg"
	invalid
	error="A summary is required."
	required
></xoji-textarea>
<script lang="ts">
	import { Textarea } from "@xoji/svelte";
	let bio = $state("");
</script>

<Textarea label="Bio" name="bio" rows={4} bind:value={bio} placeholder="Tell us about yourself…" />

<Textarea label="Notes" rows={6} resize="none" />

<Textarea label="Summary" size="lg" invalid error="A summary is required." required />
---
import { Textarea } from "@xoji/astro";
---

<Textarea label="Bio" name="bio" rows={4} placeholder="Tell us about yourself…" />

<Textarea label="Notes" rows={6} resize="none" />

<Textarea label="Summary" size="lg" invalid error="A summary is required." required />