Browse docs
Browse docs
A multi-line input. The vertical counterpart of <TextField> — same bridge wiring, same label/helper/error chrome, plus rows and resize controls. Use it for any free-text field longer than a typical single-line value (notes, descriptions, paste areas).
import { Textarea } from '@dashforge/tw';
<Textarea name="bio" label="Tell us about yourself" rows={4} />import { DashForm } from '@dashforge/forms';
import { Textarea, Button } from '@dashforge/tw';
<DashForm onSubmit={onSubmit}>
<Textarea
name="message"
label="Your message"
rows={6}
required
rules={{ minLength: { value: 20, message: 'At least 20 characters' } }}
/>
<Button type="submit" color="primary">Send</Button>
</DashForm>Standalone:
const [value, setValue] = useState('');
<Textarea
name="notes"
value={value}
onChange={(e) => setValue(e.target.value)}
/>Markdown is supported.
import { Textarea } from '@dashforge/tw';
<Textarea
name="bio"
label="Short bio"
placeholder="A few sentences about yourself…"
rows={4}
helperText="Markdown is supported."
/><Textarea size="sm" rows={2} /> {/* compact, 2 lines visible */}
<Textarea size="md" rows={4} /> {/* default */}
<Textarea size="lg" rows={8} /> {/* spacious, hero forms */}rows controls the visible line count (= <textarea rows> HTML attribute). Default is 3.
import { Textarea, Stack } from '@dashforge/tw';
<Stack gap={3}>
<Textarea
name="vertical"
label='resize="vertical" (default)'
rows={3}
defaultValue="Drag the bottom-right corner to grow taller."
/>
<Textarea
name="none"
label='resize="none"'
rows={3}
resize="none"
defaultValue="Locked size — no drag handle."
/>
</Stack><Textarea resize="vertical" /> {/* default — user can drag-resize bottom edge */}
<Textarea resize="none" /> {/* locked at `rows` size */}
<Textarea resize="both" /> {/* horizontal + vertical (rare) */}
<Textarea resize="horizontal" /> {/* rare */}Vertical-only is the sane default. none for fixed-frame layouts (cards with strict heights).
<Textarea
name="bio"
label="Bio"
helperText="Markdown supported. Keep it under 280 characters for the preview to look right."
rows={4}
/>
<Textarea
name="bio"
label="Bio"
error
helperText="Bio is required to publish."
/><RadioGroup name="contactPref" options={[{value:'email'},{value:'detail'}]} />
<Textarea
name="contactDetail"
label="Tell us more"
visibleWhen={(engine) => engine.getNode('contactPref')?.value === 'detail'}
rows={5}
required
/><Textarea
name="adminNote"
label="Internal note"
rows={3}
access={{ requires: 'workspace.admin', when: 'denied:readonly' }}
/>Three when modes ('denied:hide' | 'denied:disable' | 'denied:readonly') — same semantics as TextField.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Field name (bridge integration). |
label | ReactNode | — | Field label. |
rows | number | 3 | Visible line count. |
resize | 'none' | 'vertical' | 'horizontal' | 'both' | 'vertical' | User resize behavior. |
size | 'sm' | 'md' | 'lg' | 'md' | Density. |
layout | 'stacked' | 'inline' | 'stacked' | Label position. |
required | boolean | false | Required marker + RHF rule. |
rules | RegisterOptions | — | RHF validation. |
error | boolean | false | Force error state. |
disabled | boolean | false | Disable input. |
fullWidth | boolean | false | Stretch to container width. |
value / defaultValue | string | — | Controlled / uncontrolled value. |
onChange / onBlur | event handlers | — | Native textarea events. |
visibleWhen | (engine) => boolean | — | Reactive visibility. |
access | AccessRequirement | — | RBAC gating. |
slotProps | TextareaSlotProps | — | Per-slot overrides. |
sx | string | — | Utility-class override. |
| ...rest | HTMLTextAreaElement attrs | — | maxLength, cols, wrap, spellCheck, etc. pass through. |
root · label · requiredMark · inputWrapper · input · helperText · errorText
<textarea> under the hood — maxLength, cols, wrap, spellCheck etc. pass through via rest props.useResizeObserver-style hook). For autosizing, set rows to a sensible cap and pair with maxLength; or wrap in a custom container.resize="vertical" (default) follows browser conventions and avoids the "stretchy" feeling of both that confuses non-technical users.