<Stack
width="440px"
maxWidth="100%"
>
<TextArea.Root
size="md"
variant="outline"
>
<TextArea.Label>Project description</TextArea.Label>
<TextArea.Input name="playground-description" placeholder="What will this project achieve?" />
<TextArea.HelperText>Summarize the goal in a few sentences.</TextArea.HelperText>
<TextArea.ErrorMessage>Add a project description.</TextArea.ErrorMessage>
</TextArea.Root>
</Stack>Features
- Supports
outlineandfillvariants with responsive sizes. - Grows with its content when
resizeisauto. - Shows helper text and error messages under the textarea.
- Accepts native attributes such as
maxLength. - Supports controlled and uncontrolled values.
- Supports
disabledandrequiredstates.
Anatomy
Root links the label, helper text, and error to the textarea, Label names it, and Input is the textarea and requires name. HelperText is optional.
<TextArea.Root>
<TextArea.Label>Project description</TextArea.Label>
<TextArea.Input name="description" />
<TextArea.HelperText>Summarize the goal in a few sentences.</TextArea.HelperText>
</TextArea.Root>Variants
Text Area has two visual styles: outline and fill. The default is outline.
<TextArea.Root variant="outline">
<TextArea.Label>Outline</TextArea.Label>
<TextArea.Input name="outline-notes" placeholder="Add project notes" />
</TextArea.Root>
<TextArea.Root variant="fill">
<TextArea.Label>Fill</TextArea.Label>
<TextArea.Input name="fill-notes" placeholder="Add project notes" />
</TextArea.Root>Sizes
Root size scales the text, spacing, and label. The default is md.
<TextArea.Root size="sm">
<TextArea.Label>Small</TextArea.Label>
<TextArea.Input name="small-notes" rows={2} defaultValue="Review the first draft with the design team." />
</TextArea.Root>
<TextArea.Root size="md">
<TextArea.Label>Medium</TextArea.Label>
<TextArea.Input name="medium-notes" rows={2} defaultValue="Review the first draft with the design team." />
</TextArea.Root>Responsive
size also accepts a breakpoint object.
<TextArea.Root size={{ xs: "sm", md: "md" }}>
<TextArea.Label>Notes</TextArea.Label>
<TextArea.Input name="responsive-notes" rows={2} defaultValue="Review the first draft with the design team." />
</TextArea.Root>Automatic Height
Input rows sets its height, 3 by default. Root resize="auto" grows the textarea from its rows height as people type. Otherwise it scrolls longer text. Dragging to resize is disabled.
<TextArea.Root resize="auto">
<TextArea.Label>Growing notes</TextArea.Label>
<TextArea.Input name="growing-notes" rows={2} placeholder="Add several lines of notes" />
</TextArea.Root>
<TextArea.Root>
<TextArea.Label>Fixed-height notes</TextArea.Label>
<TextArea.Input name="fixed-notes" rows={2} placeholder="Add several lines of notes" />
</TextArea.Root>Controlled Value and Character Limit
Use value with onChange to control the text. Set limits like maxLength in Input attributes and count from the same state.
"use client";
import { TextArea } from "@vortexlabs/vortex";
import { useState } from "react";
export const TextAreaCountExample = () => {
const [value, setValue] = useState("");
return (
<TextArea.Root resize="auto">
<TextArea.Label>Project summary</TextArea.Label>
<TextArea.Input
name="summary"
value={value}
onChange={({ value }) => setValue(value)}
attributes={{ maxLength: 160 }}
/>
<TextArea.HelperText>{value.length} / 160 characters</TextArea.HelperText>
</TextArea.Root>
);
};Validation
Root error marks the textarea invalid and shows TextArea.ErrorMessage; helper text stays visible. required only adds native validation, so you decide when to set error.
<TextArea.Root error required>
<TextArea.Label>Reason for the change</TextArea.Label>
<TextArea.Input name="change-reason" />
<TextArea.ErrorMessage>Explain why this change is needed.</TextArea.ErrorMessage>
<TextArea.HelperText>Include the impact on your team.</TextArea.HelperText>
</TextArea.Root>Disabled and Read Only
Root disabled blocks editing and focus. readOnly in Input attributes keeps the text focusable and selectable.
<TextArea.Root disabled>
<TextArea.Label>Locked notes</TextArea.Label>
<TextArea.Input name="locked-notes" defaultValue="This project has been archived." />
</TextArea.Root>
<TextArea.Root>
<TextArea.Label>Release notes</TextArea.Label>
<TextArea.Input name="release-notes" defaultValue="Added project templates and improved search." attributes={{ readOnly: true }} />
</TextArea.Root>Accessibility
TextArea.Label; a placeholder doesn't replace it. Helper text and the error message are linked to the textarea automatically.TextArea.ErrorMessage when it appears.