Textarea is a multi-line text input. For freeform AI instructions (the prompt box a user types into to direct an agent), prefer .ods-composer instead — per the AGENTS.md decision table, a bare Textarea is for general multi-line form fields, not the primary AI input surface.
Installation
HTML — already included if you loaded the 3 stylesheets — see the Installation guide.
React
npm install @operant/ui
@operant/ui is currently a monorepo workspace package, not yet published to the public npm registry.
Usage
HTML
<textarea class="ods-textarea" placeholder="Describe what you want the agent to do…"></textarea>
React
import { Textarea } from "@operant/ui";
export default function Example() {
return <Textarea placeholder="Describe what you want the agent to do…" />;
}
Examples
Basic
HTML
<textarea class="ods-textarea" placeholder="Describe what you want the agent to do…"></textarea>
React
<Textarea placeholder="Describe what you want the agent to do…" />
Invalid
Pass invalid (React) or add the .is-invalid class directly (HTML) to tint the border --color-danger. In React, aria-invalid is set automatically from invalid unless you explicitly override it.
HTML
<textarea class="ods-textarea is-invalid" aria-invalid="true"></textarea>
React
<Textarea invalid defaultValue="" />
As a labeled field
Pair with Field / FieldLabel / FieldHint from the Input component set for a complete labeled form field with supplementary guidance text.
HTML
<div class="ods-field">
<label class="ods-label" for="prompt">Prompt</label>
<textarea class="ods-textarea" id="prompt"
placeholder="Summarize the last 24h of incidents and cite the sources you used."></textarea>
<span class="ods-hint">Markdown and <code>{variable}</code> interpolation are supported.</span>
</div>
React
import { Field, FieldLabel, FieldHint } from "@operant/ui";
import { Textarea } from "@operant/ui";
<Field style={{ width: 420 }}>
<FieldLabel htmlFor="prompt">Prompt</FieldLabel>
<Textarea
id="prompt"
placeholder="Summarize the last 24h of incidents and cite the sources you used."
/>
<FieldHint>Markdown and `{"{"}variable{"}"}` interpolation are supported.</FieldHint>
</Field>
Invalid field with an error message
FieldError renders role="alert" so the validation message is announced immediately, per AGENTS.md #8 ("errors via role=alert").
HTML
<div class="ods-field">
<label class="ods-label" for="prompt-invalid">Prompt</label>
<textarea class="ods-textarea is-invalid" id="prompt-invalid" aria-invalid="true"></textarea>
<span class="ods-error-text" role="alert">A prompt is required to start a run.</span>
</div>
React
import { Field, FieldLabel, FieldError } from "@operant/ui";
import { Textarea } from "@operant/ui";
<Field style={{ width: 420 }}>
<FieldLabel htmlFor="prompt-invalid">Prompt</FieldLabel>
<Textarea id="prompt-invalid" invalid defaultValue="" />
<FieldError>A prompt is required to start a run.</FieldError>
</Field>
API Reference
<Textarea>
Extends React.TextareaHTMLAttributes<HTMLTextAreaElement> — every native <textarea> attribute (rows, maxLength, onChange, disabled, etc.) is forwarded to the underlying element.
| Prop | Type | Default | Description |
|---|---|---|---|
invalid | boolean | false | Applies .is-invalid and, unless aria-invalid is explicitly passed, sets aria-invalid={true} automatically. |
className | string | — | Merged with .ods-textarea. |
ref | Ref<HTMLTextAreaElement> | — | Forwarded to the underlying <textarea>. |
HTML-side classes: .ods-textarea (shares base sizing/border/focus rules with .ods-input/.ods-select; adds resize: vertical and a min-height: 84px floor), .is-invalid (tints the border to --color-danger). Pair with .ods-field / .ods-label / .ods-hint / .ods-error-text for a complete field (see the Input component docs).
Accessibility
invalidwiresaria-invalidautomatically — screen readers announce the invalid state even if you forget to set the ARIA attribute yourself. Passaria-invalidexplicitly only if you need to override this behavior.- Focus is visible via
:focus→--shadow-focus(textarea uses:focus, not:focus-visible, since typing directly into a field is itself an intentional keyboard/pointer action). - Always associate a
<label>(FieldLabel htmlFor=/<label for=>) with the textarea'sid— a placeholder alone is not an accessible label and disappears once text is entered. - Pair an invalid textarea with a
FieldError/.ods-error-text[role="alert"]describing what's wrong — the red border alone is not sufficient (AGENTS.md#4: color alone is never the only signal). - The
resize: verticalbehavior lets users expand the control to see more of what they've typed — don't override it toresize: nonefor freeform content.