Textarea
Multi-line text input for product forms, feedback, notes, and longer user-generated content in PyColors UI.
Multi-line input for longer user intentLink to section
The Textarea component captures longer text than a standard Input.
Use it for:
- feedback messages
- support requests
- product descriptions
- notes
- prompts
- comments
- longer form fields
Textarea follows the same field model as Input: label, helper text, error state, generated id, and accessible descriptions.
Core idea
Use Textarea when the user needs space to express intent, context, or explanation.
ImportLink to section
import { Textarea } from "@pycolors/ui";Basic usageLink to section
Use a label to make the field clear and accessible.
import { Textarea } from "@pycolors/ui";
export function BasicTextarea() {
return (
<Textarea
label="Message"
placeholder="Tell us what you are building..."
/>
);
}Label rule
Prefer a visible label. Use placeholder text for examples, not as the only field description.
When to use TextareaLink to section
Use Textarea when one line is not enough for the task.
Feedback
Descriptions
Notes
Helper textLink to section
Use helper text to explain what kind of answer is expected.
Describe the product, target users, and current constraints.
import { Textarea } from "@pycolors/ui";
export function TextareaHelperText() {
return (
<Textarea
label="Project description"
helperText="Describe the product, target users, and current constraints."
placeholder="A SaaS starter for founders who want to ship faster..."
/>
);
}Helper text rule
Helper text should reduce uncertainty. Keep it short, concrete, and connected to the task.
Error stateLink to section
Use the error prop for validation errors. It automatically sets aria-invalid, aria-errormessage, and error styling.
Launch notes must contain at least 20 characters.
import { Textarea } from "@pycolors/ui";
export function TextareaError() {
return (
<Textarea
label="Launch notes"
placeholder="Summarize the release..."
error="Launch notes must contain at least 20 characters."
/>
);
}Validation rule
Error text should explain what failed and how to fix it. Avoid vague messages like “Invalid value”.
Required fieldsLink to section
Use required for mandatory fields. The label displays a destructive asterisk and the textarea receives aria-required.
Include the page, expected behavior, and what happened.
import { Textarea } from "@pycolors/ui";
export function TextareaRequired() {
return (
<Textarea
required
label="Support request"
helperText="Include the page, expected behavior, and what happened."
placeholder="I expected..."
/>
);
}SizesLink to section
Textarea supports three design-system sizes: sm, md, and lg.
import { Textarea } from "@pycolors/ui";
export function TextareaSizes() {
return (
<div className="grid gap-4">
<Textarea
size="sm"
label="Small"
placeholder="Compact notes..."
/>
<Textarea
size="md"
label="Medium"
placeholder="Default textarea..."
/>
<Textarea
size="lg"
label="Large"
placeholder="Longer product description..."
/>
</div>
);
}Size guidanceLink to section
| Size | Best for |
|---|---|
sm | Compact notes, admin tables, dense forms |
md | Default forms and settings pages |
lg | Long descriptions, prompts, support messages |
Resize behaviorLink to section
The resize prop controls how users can resize the field.
import { Textarea } from "@pycolors/ui";
export function TextareaResize() {
return (
<div className="grid gap-4">
<Textarea
label="Vertical resize"
resize="vertical"
placeholder="Default behavior..."
/>
<Textarea
label="No resize"
resize="none"
placeholder="Fixed textarea..."
/>
</div>
);
}Available resize optionsLink to section
| Resize | Behavior |
|---|---|
vertical | User can resize height |
none | Fixed size |
horizontal | User can resize width |
both | User can resize width and height |
Resize rule
Prefer vertical for most product forms. Avoid horizontal resize in constrained layouts.
Feedback formLink to section
Send feedback
Tell us what would make PyColors more useful.
Share the problem, context, and expected improvement.
import { Button, Textarea } from "@pycolors/ui";
export function FeedbackForm() {
return (
<div className="rounded-2xl border border-border/60 bg-card p-5">
<div className="mb-4">
<div className="text-sm font-medium text-foreground">
Send feedback
</div>
<div className="mt-1 text-sm text-muted-foreground">
Tell us what would make PyColors more useful.
</div>
</div>
<Textarea
label="Feedback"
helperText="Share the problem, context, and expected improvement."
placeholder="I would like..."
/>
<div className="mt-4 flex justify-end">
<Button>Send feedback</Button>
</div>
</div>
);
}Prompt fieldLink to section
Be specific about the audience, output format, and constraints.
import { Textarea } from "@pycolors/ui";
export function PromptTextarea() {
return (
<div className="rounded-2xl border border-border/60 bg-card p-5">
<Textarea
size="lg"
resize="vertical"
label="AI prompt"
helperText="Be specific about the audience, output format, and constraints."
placeholder="Generate a premium SaaS landing page section for..."
/>
</div>
);
}Usage patternsLink to section
Use Textarea for longer answers
Use Input for short values. Use Textarea when the user needs to provide context, explanation, or multi-line content.
Keep labels explicit
The label should describe the content expected from the user, not the UI element itself.
Add helper text for complex fields
Use helper text when the field needs examples, constraints, or formatting guidance.
Validate with actionable errors
Error messages should explain what to change, not just that the value is invalid.
Choose resize intentionally
Use vertical resize for flexible content. Use no resize for controlled surfaces like sheets and compact cards.
Textarea vs InputLink to section
| Situation | Use |
|---|---|
| Name, email, URL, slug | Input |
| Search query | Input |
| Short title | Input |
| Feedback message | Textarea |
| Product description | Textarea |
| Notes or comments | Textarea |
| AI prompt | Textarea |
Decision rule
If the expected answer can fit naturally on one line, use Input. If the user needs to explain something, use Textarea.
APILink to section
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Accessible label displayed above the textarea |
helperText | string | — | Supporting text shown when there is no error |
error | string | — | Error text and validation styling |
size | "sm" | "md" | "lg" | "md" | Design-system size |
resize | "none" | "vertical" | horizontal" | "both" | "vertical" | Native resize behavior |
className | string | — | Additional Tailwind classes |
...props | React.TextareaHTMLAttributes<HTMLTextAreaElement> | — | Native textarea attributes |
TypeScript typesLink to section
export type TextareaSize = "sm" | "md" | "lg";
export type TextareaResize = "none" | "vertical" | "horizontal" | "both";
export interface TextareaProps
extends Omit<
React.TextareaHTMLAttributes<HTMLTextAreaElement>,
"size"
>,
VariantProps<typeof textareaVariants> {
label?: string;
helperText?: string;
error?: string;
size?: TextareaSize;
resize?: TextareaResize;
}AccessibilityLink to section
labelis connected to the textarea withhtmlFor.- A stable id is generated with
React.useIdwhen no id is provided. helperTextis connected witharia-describedby.erroris connected witharia-errormessage.errorsetsaria-invalid.requiredsetsaria-required.- Do not rely on placeholder text as the only accessible description.
Accessibility rule
Every textarea should have a clear label. Helper text and error text should clarify the task, not replace the label.
Prefer / avoidLink to section
Prefer
- visible labels
- clear helper text for complex inputs
- specific and actionable errors
- vertical resize for longer content
- textarea for explanation-heavy fields
Avoid
- placeholder-only labels
- vague errors like “Invalid value”
- horizontal resize in responsive layouts
- using textarea for short one-line values
- asking for too much text without guidance