New
Textarea
A multi-line text input following the same conventions as Input — labels, helper text, error states, and three sizes.
Preview
Markdown is supported.
States
This field is required.
Sizes
| Size | Font size | Padding |
|---|---|---|
| sm | 12px | 6px 10px |
| md | 13px | 8px 12px |
| lg | 15px | 10px 16px |
Implementation
Textarea.tsx
tsx
import { Textarea } from "@/components/ui/Textarea";
import { useState } from "react";
// Basic with label
<Textarea label="Description" placeholder="Describe your project…" />
// Controlled
const [value, setValue] = useState("");
<Textarea
label="Bio"
helperText="Max 280 characters."
value={value}
onChange={(e) => setValue(e.target.value)}
rows={3}
/>
// Error state
<Textarea
label="Feedback"
error="Feedback cannot be empty."
defaultValue=""
/>
// Disabled
<Textarea
label="Notes"
defaultValue="These notes are read-only."
disabled
/>Props
All native <textarea> attributes are forwarded. Custom props are listed below.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Visible label rendered above the textarea. |
helperText | string | — | Supplemental hint rendered below the textarea. |
error | string | — | Error message. Replaces helperText and applies error styling. |
inputSize | "sm" | "md" | "lg" | "md" | Controls padding and font size. Does not constrain height — use rows or CSS for that. |
rows | number | 4 | Number of visible text rows. The textarea is vertically resizable by the user. |
ARIA roles
| Element | Role | Key attributes |
|---|---|---|
| Textarea | textbox (implicit) | aria-multiline='true', aria-label / aria-labelledby, aria-invalid, aria-describedby, aria-required |
Keyboard
| Key | Action |
|---|---|
| All text editing keys | Standard text editing — type, delete, navigate the cursor |
| Tab | Move focus out of the textarea to the next focusable element |
| Shift+Tab | Move focus to the previous focusable element |
Accessibility
- →Built on a native <textarea> element — keyboard focusable and screen-reader accessible.
- →The label prop renders a <label> element associated via htmlFor.
- →Error messages appear as visible text below the field; pair with aria-describedby for screen readers.
- →Vertical resize is enabled by default (resize-y) — do not disable it as it aids users who need larger input areas.
- →Character count limits should be communicated with a visible counter and aria-live for screen reader updates.