Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Textarea

A styled native textarea for multi-line text — error and disabled states, a focus border tint, and an optional auto-grow mode.

Status
stable
Since
0.1.0
Accessibility pattern
native textarea

Last updated

Install

Add Textarea from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/textarea

Usage

import { Textarea } from "@/components/ui/textarea";

<Textarea placeholder="Tell us about your project…" />;

Textarea is a thin wrapper over the native <textarea>, so every standard attribute (value/defaultValue, onChange, name, rows, required, readOnly, maxLength, …) works as expected, and its ref forwards to the underlying element. It shares its border and token styling with Input so the two fields look identical.

Examples

States

The field reflects disabled, readOnly, and aria-invalid. The invalid state re-colors the border with the destructive token — pair it with a visible error message for non-color-dependent feedback. It resizes vertically by default; the last example below uses autoGrow to size to its content instead.

Sizes

sm / md / lg. A multiline field sizes by minimum height and padding rather than the fixed control heights a single-line Input uses — a textarea grows with its content, so a fixed height would be the wrong contract — and sm steps the type down a tier with it.

<Textarea size="sm" aria-label="Compact" />
<Textarea size="md" aria-label="Default" />
<Textarea size="lg" aria-label="Roomy" />

Auto-grow

Pass autoGrow to grow the field to fit its content instead of scrolling, using native CSS field-sizing: content. Set a starting height with rows and cap the growth with a max-h-* utility via className. The first field below is a normal fixed-height textarea (it scrolls); the second is the live autoGrow field — type into it (or edit the text) and it grows line by line until it hits the max-h-40 cap, then scrolls.

<Textarea autoGrow rows={2} className="max-h-40" placeholder="Auto-grows…" />

Playground

Try every size with the auto-grow, disabled, and invalid states, then copy the generated JSX.

<Textarea placeholder="Tell us about your project…" />

API Reference

PropTypeDefaultDescription
autoGrowbooleanfalseWhen true, the field grows to fit its content instead of scrolling, using native CSS field-sizing: content. Combine with rows for a starting height and the max-h-* utility (via className) for a cap. Falls back to a fixed, scrollable height in browsers without support.
renderComponentRenderFn<HTMLProps, FieldControlState> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>><textarea />Base UI's polymorphic render prop (§7.6). Defaults to a native <textarea>; pass an element to swap the rendered node while keeping the Field wiring and the token chrome.
size"lg" | "md" | "sm"'md'Density tier — sm compact, default, lg roomy. Multiline fields scale by min-height + padding (register P1-04).

Data attributes and CSS variables on Textarea

AttributeValues
data-sizemirrors a prop or state value
data-slot"textarea"

Accessibility

  • Renders a native <textarea> — always associate a visible <label> (wrap it or use htmlFor/id); use aria-label only when a visible label is impossible.
  • The surface uses outline-hidden — a transparent 2px outline, not a removed one — and replaces it with the text-field focus treatment: on focus the border re-colors with the ring token (focus:border-ring/(--alpha-tint-border)). The darkened border is the sole focus cue in normal colours, matching Input. Under forced-colors: active the border tint is erased by the forced palette, and the transparent outline is what that palette repaints — which is why the outline is hidden rather than removed.
  • Set aria-invalid (and aria-describedby pointing at the error text) to mark a field invalid; the styling is token-driven and never relies on color alone. Focus outranks invalid: while the textarea is focused the border carries the ring tint, and the destructive tint returns on blur — the border is the field's only focus cue, so nothing else may hold it.
  • The resize handle and autoGrow are visual conveniences only — keyboard and screen-reader interaction is the standard native <textarea> behavior.
ContractStates tested
Behaviourdefault, disabled, error, invalid
Accessibilityinvalid, semantic-html
Visualdefault, focus, disabled, invalid, error, dark

Do / Don't

Do
Pair every textarea with a label and, when invalid, an aria-describedby error message.
Don't
Use aria-invalid styling as the only error signal, or rely on placeholder text as a label.

On this page