Textarea
Multi-line text input component with various features like auto-resize, character counting, and validation.
Default Textarea
A basic textarea with minimal styling, focus states, and responsive behavior.
'use client'export function DefaultTextarea({placeholder = "Enter your message...",value,onChange,rows = 4,className = "",...props}) {return (<textareavalue={value}onChange={onChange}placeholder={placeholder}rows={rows}className={`w-full px-3 py-2 text-sm bg-neutral-800 border border-white/10 rounded-md text-white placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-white/20 focus:border-transparent hover:border-white/20 transition-colors resize-vertical ${className}`}{...props}/>)}
Textarea with Label
Textarea with label, helper text, and required field indicator for forms and user input.
Please provide detailed feedback to help us improve.
'use client'export function TextareaWithLabel({label = "Message",placeholder = "Type your message here...",value,onChange,rows = 4,helperText = "",required = false,className = "",...props}) {return (<div className="w-full space-y-2"><label className="block text-sm font-medium text-white/90">{label}{required && <span className="text-red-400 ml-1">*</span>}</label><textareavalue={value}onChange={onChange}placeholder={placeholder}rows={rows}required={required}className={`w-full px-3 py-2 text-sm bg-neutral-800 border border-white/10 rounded-md text-white placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-white/20 focus:border-transparent hover:border-white/20 transition-colors resize-vertical ${className}`}{...props}/>{helperText && (<p className="text-xs text-white/50">{helperText}</p>)}</div>)}
Auto Resize Textarea
Automatically grows and shrinks based on content with configurable min and max rows.
'use client'import { useEffect, useRef } from 'react'export function AutoResizeTextarea({placeholder = "Start typing and I'll grow...",value,onChange,minRows = 3,maxRows = 10,className = "",...props}) {const textareaRef = useRef(null)const adjustHeight = () => {const textarea = textareaRef.currentif (!textarea) return// Reset height to get accurate scrollHeighttextarea.style.height = 'auto'// Calculate line heightconst lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight)const paddingTop = parseInt(window.getComputedStyle(textarea).paddingTop)const paddingBottom = parseInt(window.getComputedStyle(textarea).paddingBottom)// Calculate min and max heightsconst minHeight = lineHeight * minRows + paddingTop + paddingBottomconst maxHeight = lineHeight * maxRows + paddingTop + paddingBottom// Set new height within boundsconst newHeight = Math.min(Math.max(textarea.scrollHeight, minHeight), maxHeight)textarea.style.height = `${newHeight}px`}useEffect(() => {adjustHeight()}, [value])const handleChange = (e) => {onChange?.(e)adjustHeight()}return (<textarearef={textareaRef}value={value}onChange={handleChange}placeholder={placeholder}className={`w-full px-3 py-2 text-sm bg-neutral-800 border border-white/10 rounded-md text-white placeholder-neutral-400 focus:outline-none focus:ring-2 focus:ring-white/20 focus:border-transparent hover:border-white/20 transition-colors resize-none overflow-hidden ${className}`}style={{ minHeight: `${minRows * 1.5 + 1}rem` }}{...props}/>)}
Textarea with Counter
Character counter with visual feedback for limits. Changes color as you approach the maximum.
0/150
'use client'import { useState } from 'react'export function TextareaWithCounter({placeholder = "Share your thoughts...",value: controlledValue,onChange,maxLength = 280,rows = 4,label = "Description",showCounter = true,className = "",...props}) {const [internalValue, setInternalValue] = useState('')// Use controlled value if provided, otherwise use internal stateconst value = controlledValue !== undefined ? controlledValue : internalValueconst currentLength = value?.length || 0const isNearLimit = currentLength > maxLength * 0.8const isOverLimit = currentLength > maxLengthconst handleChange = (e) => {const newValue = e.target.valueif (controlledValue !== undefined) {onChange?.(e)} else {setInternalValue(newValue)onChange?.(e)}}const getCounterColor = () => {if (isOverLimit) return 'text-red-400'if (isNearLimit) return 'text-yellow-400'return 'text-white/50'}const getBorderColor = () => {if (isOverLimit) return 'border-red-500/50 focus:ring-red-500/20'return 'border-white/10 focus:ring-white/20 hover:border-white/20'}return (<div className="w-full space-y-2">{label && (<label className="block text-sm font-medium text-white/90">{label}</label>)}<div className="relative"><textareavalue={value}onChange={handleChange}placeholder={placeholder}rows={rows}maxLength={maxLength}className={`w-full px-3 py-2 text-sm bg-neutral-800 border rounded-md text-white placeholder-neutral-400 focus:outline-none focus:ring-2 focus:border-transparent transition-colors resize-vertical ${getBorderColor()} ${className}`}{...props}/>{showCounter && (<div className="flex justify-between items-center mt-2"><div className="text-xs text-white/50">{isOverLimit && "Character limit exceeded"}</div><div className={`text-xs font-medium ${getCounterColor()}`}>{currentLength}/{maxLength}</div></div>)}</div></div>)}
