Textarea
A styled native textarea for multi-line text — it grows with its content, and signals focus with a subtle darker border rather than a ring.
- Status
- Since
0.1.0- Accessibility pattern
- native textarea
Last updated
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Textarea before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify textareaInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/textareaRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
Usage
import { Textarea } from "@/components/ui/textarea";
<Textarea placeholder="Type your message here." />;Examples
Field
Use Field, FieldLabel and FieldDescription to give the textarea a label and helper text. Inside
a Field the textarea is labelled and described with no ids to wire (API-26).
Enter your message below.
Disabled
Use disabled, and add data-disabled to the Field so the label dims with it.
Invalid
Add data-invalid to the Field, and the textarea inside it is marked aria-invalid for you (or
pass aria-invalid on a standalone textarea). The destructive border holds in
every state: focus never replaces it with the darker focus border (FOC-14).
Button
Pair with a Button to make a submit composition.
RTL
The padding is written in logical properties, so a right-to-left document mirrors it without any extra work.
Share your thoughts about our service.
شاركنا أفكارك حول خدمتنا.
States
Rest, filled, invalid and disabled in one frame. Click or Tab into a textarea to see the focus state:
the border darkens subtly (border-ring/50) over 150ms and no fill is painted; the invalid one keeps
its destructive border while focused.
Playground
Try the starting height with the disabled and invalid states, then copy the generated JSX.
<Textarea rows={4} placeholder="Tell us about your project…" />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
size | "default" | "lg" | null | — | |
submitOnEnter | boolean | false | Enter submits the textarea's form (form.requestSubmit()) instead of adding a line; Shift+
Enter still adds one, and Enter while an IME is composing is left alone. For a title that
wraps but is one paragraph. |
variant | "default" | "ghost" | null | — |
Accessibility
- Renders a native
<textarea>, so the platform owns selection, IME composition and spellcheck. - Focus is a subtle darker border (
border-ring/50, easing in over 150ms), not a ring, and no background change — text entry is the one exception to FOC-14's fixed border (MK 2026-09-27); the global outline is suppressed withoutline-hidden(FOC-8). It fires on:focus, for mouse and keyboard alike, because a text field cannot tell them apart and both need the caret located. An invalid textarea keeps its destructive border while focused. - Under
forced-colors: activethe border colour is replaced with every authored colour, sobase.csspaints a 2pxHighlightoutline ontextarea:focusinstead (FOC-7). field-sizing: contentgrows the box with the text, so nothing is hidden behind a scrollbar at small sizes.- Give it a label: a
FieldLabelin the sameField(wired automatically), or anaria-label.
| Contract | States tested |
|---|---|
| Behaviour | default, disabled, invalid |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test, invalid, disabled |
| Visual | default, focus, invalid, disabled |
Do / Don't
Deviations
Upstream's file plus packages/ui/upstream/patches/textarea.patch. Every hunk:
- FOC-1, FOC-3, FOC-6, FOC-8 —
outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50becomesoutline-hidden, with no ring and no glow.outline-hiddenrather thanoutline-none, so the forced-colours fallback has something to repaint. - FOC-14 — the invalid border is
aria-invalid:border-destructive(and its dark counterpart), held in every state, focused or not; thearia-invalidhalo rings are removed with the rest. - FOC-14 text-entry exception (MK 2026-09-27) — the textarea adds
focus:not-aria-invalid:border-ring/50withtransition-[color,background-color,border-color] duration-150 ease-out: a subtle darker border that eases in, and no fill (base.cssexcludestextareafrom the background tint). Thenot-aria-invalidguard keeps the destructive border. - API-26 — the
<textarea>renders through Base UIField.Control, so inside aFieldit takes its label, the rendered description and error ids, andaria-invalidwith no props, likeInput. The file gains"use client", becauseField.Controlis hook-backed. - API-40 —
variant(default·ghost) andsize(default·lg), as onInput, andsubmitOnEnter.ghostis borderless and transparent, starts at one row and grows with its text (a measured height where the browser lacksfield-sizing: content);lgis the heading size; withsubmitOnEnter, Enter submits the form and Shift+Enter adds a line. For a big title that may wrap:<Textarea variant="ghost" size="lg" submitOnEnter />. - DOC-2 —
cnis imported from@vegastack/design.