affectUI › Components › Inputs
Text Area
The multi-line twin of the Text Field – grows with the text, a character count, a button for more room and ⌘ Enter to send.
Free and open source (MIT). Install: npx shadcn@latest add https://www.affectui.com/r/text-area.json · Import from @/components/ui/text-area
When to use
- Anything longer than a line in a form: descriptions, notes, bios, feedback, instructions or context for an assistant
- Settings and creation dialogs next to Text Fields – same label, hint, error and focus, so a form reads as one
When not to use
- A single line – names, emails, URLs – use the Text Field
- Writing to an assistant or a person with send, attachments or a model picker – use the Chat Composer
Usage
import { useState } from "react";
import { TextArea } from "@/components/ui/text-area";
export function CompanyContext({ onSave }: { onSave: (text: string) => void }) {
const [text, setText] = useState("");
return (
<TextArea
label="Company context"
hint="Added to every chat in this workspace."
value={text}
onChange={(e) => setText(e.target.value)}
maxLength={2000}
counter
minRows={3}
maxRows={8}
expandable
onSubmitShortcut={onSave}
/>
);
}Props
| Name | Type | Default | Description |
|---|---|---|---|
label | ReactNode | Shown above the field; clicking it focuses the textarea | |
hint | ReactNode | A quiet line under the field – the error takes its place while there is one | |
error | ReactNode | Marks the field invalid (red edge and a faint red fill, aria-invalid) and shows the message where the hint was | |
optional | boolean | false | Adds "Optional" next to the label |
counter | boolean | false | Shows "120/2,000" under the field, red once a prefilled value is over the limit; needs maxLength |
minRows | number | 3 | Height when empty, in lines |
maxRows | number | 10 | It grows with the text up to this many lines, then scrolls inside |
expandable | boolean | false | A small button in the top corner that gives the field more room – and back |
expandedRows | number | 16 | Lines while expanded |
expanded | boolean | Controls the expanded state from outside; pair with onExpandedChange | |
onExpandedChange | (expanded: boolean) => void | Called when the button gives more or less room | |
onSubmitShortcut | (value: string) => void | ⌘/Ctrl+Enter – save or send without reaching for the mouse; Enter alone still makes a new line | |
inputClassName | string | Extra class on the textarea itself, e.g. a monospace font for prompts | |
className | string | Extra class on the wrapper | |
...textarea props | ComponentProps<"textarea"> | Everything else – value, defaultValue, onChange, name, placeholder, required, disabled, readOnly, maxLength, ref – goes to the textarea |
Keyboard
- Enter: A new line
- ⌘ / Enter: Calls onSubmitShortcut (Ctrl+Enter on Windows and Linux)
- Tab: Moves on to the More room button, then out of the field
Accessibility
- A real <textarea> with a <label> tied to it – works with forms, autofill and screen readers
- The hint, the error and the count are linked with aria-describedby; an error sets aria-invalid and is announced politely
- The More room button reports its state with aria-pressed and points at the field with aria-controls; the shortcut is listed in aria-keyshortcuts
- Without a label, a text placeholder becomes the field's accessible name – better still, pass aria-label
Responsive
- Fills its container; it measures again when its width changes, because the text wraps differently
- On touch screens it uses 16px text, so iOS doesn't zoom in on focus, and the corner button grows to 32px
- Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"
Requirements
- React 19
Related
- Text Field – One input for every form – label, hint and error in place, prefix and suffix, clear, show-password and copy buttons, a character count
- Chat Composer – Prompt composer with model picker, voice input, app connections and approval request
- Button – Primary, secondary, ghost and destructive buttons with icons, sizes and a shimmering loading state
- Stepper Form – A multi-step flow for onboarding and setup – steps that fill and check off, sliding steps, a card that morphs to each step, inline validation and a success state