Skip to content
Component installs need the registry setup
VegaStack Design

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
stable
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 textarea

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/textarea

Run 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

PropTypeDefaultDescription
size"default" | "lg" | null—
submitOnEnterbooleanfalseEnter 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 with outline-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: active the border colour is replaced with every authored colour, so base.css paints a 2px Highlight outline on textarea:focus instead (FOC-7).
  • field-sizing: content grows the box with the text, so nothing is hidden behind a scrollbar at small sizes.
  • Give it a label: a FieldLabel in the same Field (wired automatically), or an aria-label.
ContractStates tested
Behaviourdefault, disabled, invalid
Accessibilitynative-or-base-ui-semantics, browser-accessibility-test, invalid, disabled
Visualdefault, focus, invalid, disabled

Do / Don't

Do
Use a Textarea for free-form multi-line text — a description, a comment, a note.
Don't
Use a Textarea for rich text — that is the editor.

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/50 becomes outline-hidden, with no ring and no glow. outline-hidden rather than outline-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; the aria-invalid halo rings are removed with the rest.
  • FOC-14 text-entry exception (MK 2026-09-27) — the textarea adds focus:not-aria-invalid:border-ring/50 with transition-[color,background-color,border-color] duration-150 ease-out: a subtle darker border that eases in, and no fill (base.css excludes textarea from the background tint). The not-aria-invalid guard keeps the destructive border.
  • API-26 — the <textarea> renders through Base UI Field.Control, so inside a Field it takes its label, the rendered description and error ids, and aria-invalid with no props, like Input. The file gains "use client", because Field.Control is hook-backed.
  • API-40 — variant (default · ghost) and size (default · lg), as on Input, and submitOnEnter. ghost is borderless and transparent, starts at one row and grows with its text (a measured height where the browser lacks field-sizing: content); lg is the heading size; with submitOnEnter, 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 — cn is imported from @vegastack/design.

On this page