Textarea

A multi-line hand-drawn text field with an optional label, error message, and auto-resize.

Overview

A multi-line text field for collecting longer, free-form data, with an optional visible label, (on React) an error message, and an opt-in autoResize mode that grows the field to fit its content instead of scrolling.

Anatomy

An optional label above a sketchy-outlined text box; on React, an error message renders below the box as a role="alert" element when error is set. The native resize handle is always disabled — it visually collides with the hand-drawn border, so growth (when autoResize is set) is the only way the box changes size.

Variants & States

State Status Notes
Default Implemented
Focused Implemented Stroke color swaps to a focus token.
Disabled Implemented
Error / invalid Implemented React only — aria-invalid + aria-describedby + role="alert". Not implemented on Web Components or React Native, matching Input.
Auto-resize Implemented Opt-in via autoResize. Measures scrollHeight (or onContentSizeChange on React Native) in JS rather than CSS field-sizing, for cross-browser determinism.
Loading Not implemented

Web Components instead has required (native constraint validation via ElementInternals) — React and React Native don’t expose that as a prop at all. These are two separate, real gaps, not documentation omissions — same platform split as Input.

Usage

Do

  • Use Textarea for free-form, multi-line input (comments, bios, feedback) — use Input for a single line of text.
  • Set autoResize for short-to-medium free-form fields where scrolling inside a fixed box would hide content the user just typed.

Don't

  • Don't rely on placeholder text as the only accessible name — it disappears once the user types.
  • Don't expect autoResize to cap growth — v1 has no minRows/maxRows or a max-height-with-scroll option; the box grows to fit all typed content.

Accessibility

Content

The label names the data being collected (“Bio”, “Feedback”), not an action — contrast with Button, whose label names an action. Error messages state what’s wrong and how to fix it.

Props API

React@ghds/react

PropTypeDefaultDescription
labelstringVisible label, associated via Radix Label.
errorstringError message. When set, marks the field invalid and announces it.
autoResizebooleanfalseGrows the field to fit its content instead of scrolling.
disabledbooleanfalseDisables editing.
...restTextareaHTMLAttributesAll other native <textarea> attributes (value, onChange, rows, etc.) pass through.

Web Components@ghds/web-components

PropTypeDefaultDescription
valuestring''Current field value, mirrored to the form value.
namestringSubmitted control name.
placeholderstringPlaceholder text.
labelstringOptional visible label, also the accessible name.
rowsnumber2Visible row count — also the minimum height once measured.
autoResizebooleanfalseGrows the field to fit its content instead of scrolling. Reflected as autoresize.
disabledbooleanfalseDisables editing and form participation.
requiredbooleanfalseNative constraint validation. No error prop exists.

React Native@ghds/react-native

PropTypeDefaultDescription
labelstringVisible, accessible label — required (there is no separate label element on RN).
valuestringControlled text value.
onChangeText(text: string) => voidChange handler.
placeholderstringPlaceholder text.
rowsnumber2Visible row count — also the minimum height once measured. RN has no native rows attribute.
autoResizebooleanfalseGrows the field to fit its content via onContentSizeChange. No error prop exists.
disabledbooleanfalseDisables editing.
testIDstringTest handle for queries.

Code examples

// React — @ghds/react
import { Textarea } from '@ghds/react/textarea';

<Textarea
  label="Bio"
  placeholder="Tell us about yourself"
  value={bio}
  onChange={(event) => setBio(event.target.value)}
/>;
// React-only error state:
<Textarea label="Feedback" error="Feedback is required." />;
<!-- Web Components — @ghds/web-components -->
<script type="module">
  import '@ghds/web-components/textarea';
</script>
<gh-textarea label="Bio" placeholder="Tell us about yourself" autoresize></gh-textarea>
<!-- No error prop; Web Components uses native `required` instead -->
<gh-textarea label="Feedback" required></gh-textarea>
// React Native — @ghds/react-native
import { Textarea } from '@ghds/react-native/textarea';

<Textarea
  label="Bio"
  placeholder="Tell us about yourself"
  value={bio}
  onChangeText={setBio}
  autoResize
/>;

Live Demo

React’s demo includes the error state; the Web Components demo intentionally does not (it has no error prop) and shows required instead. Both demos include an autoResize example.

React @ghds/react

Web Components @ghds/web-components