Text Area
A multi-line text input with label, help text, validation, optional auto-resize and a character counter.
Preview
Installation
pnpm add @syntara/react @syntara/tokensimport { TextArea } from '@syntara/react';Usage
import { TextArea } from '@syntara/react';
export function Notes() {
return <TextArea label="What happened?" description="Include dates and amounts." maxLength={500} />;
}Examples
Character counter
Shown when maxLength is set; announced only near and at the limit.
Auto-resize
Grows with the text up to maxRows, then scrolls.
Invalid and disabled
Accessibility
| Keys | Action |
|---|---|
| Tab | Moves focus to the text area. |
| Enter | Inserts a new line. |
- The visible counter is aria-hidden; a polite live region announces only when 10% of the limit remains and when the limit is reached.
- The counter turns warning then danger colour, and the number itself changes, so it is not colour-only.
- Live-region messages are English; wrap or fork to localise.
Guidelines
Do
- Size rows to the expected answer length.
- Use maxLength with a counter when there is a real limit (e.g. a statement note).
Don’t
- Don't use a text area for single-line data like names or amounts.
- Don't set maxRows so low that people can't review what they wrote.
API reference
TextArea
labelReactNodeVisible label, linked to the control. Without one, pass aria-label.
descriptionReactNodeHelp text, linked with aria-describedby.
errorMessagestring | ((validation: ValidationResult) => string)Shown with an icon when invalid. Defaults to the browser or validate() message.
placeholderstringExample text. Not a substitute for a label.
rowsnumberVisible rows; also the minimum height when autoResize is on.
Default
3autoResizebooleanGrow with the content instead of showing a resize handle.
Default
falsemaxRowsnumberWith autoResize, stop growing after this many rows.
maxLengthnumberHard limit (native maxlength) and turns on the counter.
value / defaultValuestringControlled / uncontrolled value.
onChange(value: string) => voidCalled on every edit.
isRequiredbooleanMarks the field required (native required + a decorative asterisk on the label).
Default
falseisInvalidbooleanForces the invalid state (aria-invalid, danger border, error message).
Default
falseisDisabledbooleanDisables the field.
Default
falsevalidate(value) => string | string[] | true | null | undefinedCustom validation; return an error message to show.
inputRefRef<HTMLTextAreaElement>Ref to the underlying textarea.
Tokens
The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.
- Colour12
border.defaultborder.strongfeedback.danger.fgfeedback.danger.solidfeedback.warning.fgfocus.ringsurface.defaultsurface.sunkentext.defaulttext.disabledtext.subtlesurface.canvas- Type4
font.size.mdfont.size.xsfont.weight.mediumline-height.normal- Space and size5
control-heightcontrol-padding-inlinespace.2space.3space.1- Shape1
radius.field- Motion6
motion.duration.fastmotion.duration.normalmotion.easingmotion.easingOutmotion.duration.springmotion.spring