Skip to main content

TextareaInput Component

** Last Built**: September 2, 2025 at 4:19 PM The TextareaInput component provides a multi-line text input field for longer text content. It supports validation states, character counting, and integrates seamlessly with form systems.

Import

// TextareaInput component is available in the live scope

Basic Usage

<TextareaInput
id="description"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Enter your description..."
rows={4}
/>

Props

PropTypeDefaultDescription
idstring-Unique identifier for the textarea
namestring-Name attribute for the textarea
valuestring-Current textarea value
onChange(e: ChangeEvent<HTMLTextAreaElement>) => void-Change handler function
placeholderstring-Placeholder text
rowsnumber3Number of visible rows
colsnumber-Number of visible columns
maxLengthnumber-Maximum character limit
minLengthnumber-Minimum character requirement
disabledbooleanfalseWhether the textarea is disabled
readOnlybooleanfalseWhether the textarea is read-only
requiredbooleanfalseWhether the textarea is required
errorstring-Error message to display
helperTextstring-Helper text below the textarea
classNamestring-Additional CSS classes
size'sm' | 'md' | 'lg''md'Textarea size variant
resize'none' | 'vertical' | 'horizontal' | 'both''vertical'Resize behavior

Examples

Basic Textarea

const [bio, setBio] = useState('');
<TextareaInput
id="bio"
value={bio}
onChange={(e) => setBio(e.target.value)}
placeholder="Tell us about yourself..."
rows={5}
/>

With Character Limit

<TextareaInput
id="tweet"
value={tweet}
onChange={(e) => setTweet(e.target.value)}
placeholder="What's happening?"
maxLength={280}
helperText={`${tweet.length}/280 characters`}
rows={3}
/>

With Validation

const [description, setDescription] = useState('');
const [errors, setErrors] = useState({});
<TextareaInput
id="description"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Enter product description..."
rows={6}
required
minLength={50}
error={errors.description}
helperText="Description must be at least 50 characters long"
/>

Form Integration

function ProductForm() {
const [product, setProduct] = useState({
name: '',
description: '',
specifications: ''
});
return (
<form className="space-y-4">
<div>
<Label htmlFor="name">Product Name</Label>
<Input
id="name"
value={product.name}
onChange={(e) => setProduct(prev => ({ ...prev, name: e.target.value }))}
required
/>
</div>
<div>
<Label htmlFor="description">Description</Label>
<TextareaInput
id="description"
value={product.description}
onChange={(e) => setProduct(prev => ({ ...prev, description: e.target.value }))}
placeholder="Describe your product..."
rows={4}
required
/>
</div>
<div>
<Label htmlFor="specifications">Technical Specifications</Label>
<TextareaInput
id="specifications"
value={product.specifications}
onChange={(e) => setProduct(prev => ({ ...prev, specifications: e.target.value }))}
placeholder="List technical specifications..."
rows={6}
helperText="Include dimensions, materials, features, etc."
/>
</div>
</form>
);
}

Character Counting

function CharacterCountTextarea() {
const [content, setContent] = useState('');
const maxLength = 1000;
const remaining = maxLength - content.length;
const isNearLimit = remaining <= 100;
const isOverLimit = remaining < 0;
return (
<div>
<TextareaInput
id="content"
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Enter your content..."
rows={8}
maxLength={maxLength}
className={isOverLimit ? 'border-red-500' : isNearLimit ? 'border-yellow-500' : ''}
/>
<div className={`text-sm mt-2 ${isOverLimit ? 'text-red-600' : isNearLimit ? 'text-yellow-600' : 'text-gray-500'}`}>
{remaining} characters remaining
</div>
);
}

Resize Behavior

// No resize
<TextareaInput
id="fixed"
resize="none"
rows={4}
placeholder="Fixed size textarea"
/>
// Vertical resize only
<TextareaInput
id="vertical"
resize="vertical"
rows={4}
placeholder="Vertically resizable"
/>
// Both directions
<TextareaInput
id="both"
resize="both"
rows={4}
placeholder="Fully resizable"
/>

Accessibility

The TextareaInput component includes comprehensive accessibility features:

  • Proper ARIA labels and descriptions
  • Error state announcements for screen readers
  • Keyboard navigation support
  • Focus management
  • Screen reader compatibility
<TextareaInput
id="accessible-textarea"
aria-describedby="textarea-help textarea-error"
aria-invalid={!!errors.textarea}
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Enter your text here"
error={errors.textarea}
helperText="Provide detailed information about your request"
/>

Best Practices

  1. Use appropriate rows - Set rows based on expected content length
  2. Provide clear placeholders - Help users understand what to enter
  3. Implement character limits - Prevent overly long submissions
  4. Show character count - Help users stay within limits
  5. Use helper text - Provide additional context when needed
  6. Consider resize behavior - Allow resizing for better user experience
  • Input - For single-line text input
  • Form - For form containers and validation
  • Label - For form field labels
  • Button - For form submission and actions