Textarea
An advanced, accessible textarea component with auto-resizing, character counting, and built-in support for error, disabled, and read-only states. Ideal for forms where dynamic height and user feedback are needed.
Usage
Basic usage
import { Textarea } from '@nofinite/nui';
<Textarea placeholder="Write something..." />;
With typical interaction
<Textarea
maxLength={200}
showCount
autoGrow
placeholder="Type and watch it grow..."
onChange={(e) => console.log(e.target.value)}
/>
Variants
The Textarea component supports visual states rather than traditional variants:
<Textarea />
<Textarea error />
<Textarea disabled />
<Textarea readOnly />
Available states / visual variations:
default– normal textareaerror– displays a red border and subtle error shadowdisabled– grayed out and non-interactivereadOnly– non-editable but selectable content
Guidelines:
- Use
errorfor form validation feedback. - Use
disabledfor inactive fields. - Use
readOnlywhen content should not be modified.
Sizes
Textarea supports dynamic height via autoGrow and a default of 3 rows. You can adjust height using the rows prop:
<Textarea rows={3} />
<Textarea rows={5} autoGrow />
Notes:
autoGrowoverrides manual height to fit content.- Rows set the minimum visible height.
States
<Textarea disabled />
<Textarea readOnly />
<Textarea error />
State behavior:
disabled– prevents typing, visually muted.readOnly– allows selection but no edits.error– highlights border in red and applies shadow.showCount– displays character counter at bottom-right.
Native Props / Composition
Textarea extends native <textarea> attributes:
<Textarea
id="comment"
name="comment"
placeholder="Enter your comment"
aria-describedby="helper-text"
maxLength={200}
rows={4}
onChange={handleChange}
/>
Supports className and style for custom styling:
<Textarea className="my-custom-textarea" style={{ width: '100%' }} />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
showCount | boolean | false | Display character counter |
autoGrow | boolean | true | Automatically resize height based on content |
error | boolean | false | Apply error styling |
helperId | string | — | ID for aria-describedby linking help or error text |
rows | number | 3 | Minimum number of visible rows |
disabled | boolean | false | Disable typing |
readOnly | boolean | false | Make content non-editable |
required | boolean | false | Mark field as required |
maxLength | number | — | Maximum number of characters allowed |
value | string | — | Controlled value |
defaultValue | string | — | Initial value for uncontrolled textarea |
onChange | (e: React.ChangeEvent<HTMLTextAreaElement>) => void | — | Change event handler |
className | string | "" | Additional CSS class names |
...rest | React.TextareaHTMLAttributes<HTMLTextAreaElement> | — | Any other native textarea attributes |
Behavior Notes
- Automatically resizes height if
autoGrowistrue. - Supports both controlled (
value) and uncontrolled (defaultValue) modes. - Character counter displays live count if
showCountormaxLengthis provided. - Error and disabled states are purely visual and interactive, consistent with native
<textarea>behaviors.
<Textarea autoGrow maxLength={100} showCount error />
Accessibility
- Renders as native
<textarea>. - Supports keyboard interactions: typing, tabbing, focus.
aria-invalidapplied whenerroris true.aria-describedbycan link to helper or error text.- Character counter is marked
aria-hidden="true"to avoid screen reader clutter.
<Textarea aria-describedby="helper-text" error />
Layout
- Block-level by default, fills available width.
- Supports
style={{ width: "100%" }}for full-width layout. - Can be placed inside flex/grid layouts and will respect container sizing.
<Textarea style={{ width: '100%' }} placeholder="Full-width textarea" />
Best Practices
Do
- Use
autoGrowfor user-friendly expanding text input. - Combine with
showCountandmaxLengthfor character-limited inputs. - Apply
errorfor form validation feedback. - Use
helperIdfor linking descriptions or error messages.
Don’t
- Overuse
readOnlywhere input is expected. - Use
disabledfor hiding content — use visibility or conditional rendering instead. - Mix too many visual states in the same textarea (e.g.,
disabled+error).