Textarea

A textarea component for multi-line text input with auto-resize and scroll management

Installation

Terminal
pnpm add @choice-ui/textarea

Import

Component.tsx
import { Textarea, ResizeHandle, type TextareaProps, type TextareaContentProps, type ResizeHandleProps } from "@choice-ui/textarea"

Basic

Default: Basic textarea with auto-resize behavior and default styling.
Features:
- Auto-sizing based on content - Default visual styling - Basic placeholder text

With Value

Controlled: Demonstrates controlled textarea with state management.
Features:
- Controlled input with React state - Real-time value updates - Programmatic value control
Best Practices:
- Use controlled mode when you need to validate, format, or sync with other components - Always provide an onChange handler for controlled inputs

Variants

Variants: Demonstrates different visual variants of the textarea component.
Features:
- default: Follows the page theme dynamically (light/dark mode) - light: Fixed light appearance regardless of theme - dark: Fixed dark appearance regardless of theme - reset: Removes variant styling, no variant settings applied
Best Practices:
- Use default variant for inputs that adapt to the current theme - Use light/dark variants when you need fixed appearance - Use reset variant to remove all variant-specific styling

Reset Variant

Reset Variant: Textarea with no variant-specific styling for complete customization.
Features:
- Removes all variant-specific styles (borders, rounded corners, backgrounds) - Allows complete style customization via className - Maintains all functional features (auto-resize, scrolling, etc.) - Perfect for custom designs that don't fit standard variants
Best Practices:
- Use when you need a completely custom appearance - Apply your own borders, backgrounds, and spacing via className - Combine with custom CSS for unique designs - Still benefits from all functional features of the component
Technical Details:
- Removes: rounded-md, border, border-transparent from container - Preserves: placeholder color styling (placeholder:text-secondary-foreground) - Preserves: all functional styles (w-full, overflow-hidden, resize-none, etc.)

Basic Reset Variant

Reset variant removes all variant-specific styling, allowing complete customization.

Custom Styled Reset Variant

Apply your own styles via className for a completely custom appearance.

Another Custom Style Example

Reset variant gives you full control over the appearance.

Comparison: Default vs Reset

Selected

Selected State: Textarea in selected/focused state with visual emphasis.
Features:
- Visual indication of selection/focus - Enhanced border styling - Clear state differentiation
Best Practices:
- Use to highlight important or active textareas in complex forms - Combine with focus management for better UX

Disabled

Disabled State: Non-interactive textarea for display-only content.
Features:
- Visual disabled styling - Prevents user interaction - Maintains content visibility
Accessibility:
- Properly communicated to screen readers - Skipped in keyboard navigation

Read Only

Read-Only: Interactive but non-editable textarea for content display.
Features:
- Focusable but not editable - Supports text selection and copying - Visual indication of read-only state
Best Practices:
- Use when users need to view/copy content but not edit it - Prefer over disabled when selection/copying is needed

With Min Max Rows

Height Constraints: Textarea with minimum and maximum row limits.
Features:
- Controlled height boundaries with minRows and maxRows - Auto-sizing within defined limits - Scrolling when content exceeds maxRows
Best Practices:
- Set minRows to ensure adequate initial space - Set maxRows to prevent excessive height in layouts - Consider content length when setting limits

Without Autosize

Fixed Size: Textarea with fixed height that doesn't auto-resize.
Features:
- Fixed height based on rows prop - No automatic resizing - Scrollable content when overflow occurs
Best Practices:
- Use in grid layouts or when consistent height is required - Ensure sufficient rows for expected content - Consider UX impact of fixed sizing

Long Content

Scrollable Content: Textarea with long content demonstrating scroll behavior.
Features:
- Custom scrollbar styling via ScrollArea - Smooth scrolling experience - Height limits with maxRows causing overflow
Best Practices:
- Set appropriate maxRows for your layout - Consider character limits for very long content - Test scrolling behavior across different devices

Interactive

Interactive Example: Textarea with real-time feedback and editing state tracking.
Features:
- Real-time character counting - Editing state detection - Live feedback display
Best Practices:
- Use onIsEditingChange for form validation timing - Display character counts for limited-length fields - Provide immediate feedback to users

Character count: 0

Is editing: No

Resize Handle

Manual Resize: Textarea with drag handle for manual height adjustment.
Features:
- Draggable resize handle in bottom-right corner - Manual height control with mouse/touch - Height constraints respected during resize - Visual feedback during drag operation
Best Practices:
- Set appropriate minRows/maxRows for your layout - Use when users need precise control over textarea height - Consider mobile accessibility for touch interactions - Provide visual cues for the resize functionality
Accessibility:
- Resize handle is keyboard accessible - Clear visual indication of resize capability - Maintains focus during resize operations

Simple Usage

Simple Usage: Demonstrates the default simple usage pattern.
Features:
- Direct value and onChange props - Auto-sizing with maxRows constraint - Clean, minimal API
Character count: 0

Compound Usage

Compound Usage: Demonstrates the compound component pattern with Textarea.Content.
Features:
- Custom content component - Additional className on content - Full control over TextareaAutosize props
Using Textarea.Content with custom font-mono class

Focus Selection Modes

Focus Selection Modes: Demonstrates different focus selection behaviors.
Features:
- "all": Selects all text on focus (default) - "end": Moves cursor to end of text - "none": No selection change

focusSelection="all" - Selects all text when focused

focusSelection="end" - Moves cursor to end of text

focusSelection="none" - Maintains cursor position

No Newline Mode

No Newline Mode: Demonstrates textarea that prevents newline on Enter.
Features:
- Prevents Enter key from creating new lines - Useful for single-line input scenarios - Still allows text wrapping visually

allowNewline=false - Enter key is disabled

allowNewline=true (default) - Enter key works normally

Custom Line Height

Custom Line Height: Demonstrates the customizable lineHeight prop.
Features:
- Adjustable line height for different text densities - Automatic height calculation based on custom line height - Works with minRows and maxRows

In Popover

In Popover: Demonstrates textarea working correctly in a Popover.
This story tests the fix for the auto-height calculation bug that occurred when textarea is rendered inside a popover or dialog. The component now properly handles initialization when the container is initially hidden.
Features:
- Correct height calculation when popover opens - IntersectionObserver for visibility detection - Automatic retry mechanism for sizing data
Technical Implementation:
- Uses IntersectionObserver to detect when textarea becomes visible - Implements requestAnimationFrame retry for sizing data - Checks element connectivity and visibility before calculating height

API reference

TextareaPropsTypeDefault
value
string
|
undefined
-
onChange
((value: string) => void)
|
undefined
-
selected
boolean
|
undefined
-
className
string
|
undefined
-
allowNewline
boolean
|
undefined
true
contentRef
RefObject<HTMLDivElement>
|
undefined
-
focusSelection
undefined
|
"none"
|
"all"
|
"end"
"all"
lineHeight
number
|
undefined
16
maxRows
number
|
undefined
undefined (no maximum)
minRows
number
|
undefined
3
onIsEditingChange
((isEditing: boolean) => void)
|
undefined
-
padding
number
|
undefined
4 (py-1)
resize
false
|
"auto"
|
"handle"
|
undefined
"auto"
scrollRef
RefObject<HTMLDivElement>
|
undefined
-
variant
undefined
|
"default"
|
"light"
|
"dark"
|
"reset"
"default"
TextareaAutosizeTypeDefault
cacheMeasurements
boolean
|
undefined
true
debounceMs
number
|
undefined
0
maxRows
number
|
undefined
-
minRows
number
|
undefined
1
onHeightChange
((height: number, meta: TextareaHeightChangeMeta) => void)
|
undefined
() => {}
style
Style
|
undefined
-