|
| 1 | +# useAutosizeTextArea Hook |
| 2 | + |
| 3 | +A custom hook that automatically resizes a textarea element to fit its content, eliminating the need for manual scrolling. |
| 4 | + |
| 5 | +## Location |
| 6 | +`src/hooks/use-auto-resize-textarea.ts` |
| 7 | + |
| 8 | +## Signature |
| 9 | +```typescript |
| 10 | +function useAutosizeTextArea( |
| 11 | + textAreaRef: React.RefObject<HTMLTextAreaElement | null>, |
| 12 | + value: string, |
| 13 | + initialHeight?: string |
| 14 | +): void |
| 15 | +``` |
| 16 | + |
| 17 | +## Parameters |
| 18 | +- `textAreaRef`: React ref object pointing to the textarea element |
| 19 | +- `value`: Current text content of the textarea (triggers resize when changed) |
| 20 | +- `initialHeight` (optional): Initial height to set before auto-sizing |
| 21 | + |
| 22 | +## Returns |
| 23 | +None (void) - This hook has side effects on the referenced textarea |
| 24 | + |
| 25 | +## Usage Example |
| 26 | + |
| 27 | +```typescript |
| 28 | +import { useAutosizeTextArea } from '@/hooks/use-auto-resize-textarea'; |
| 29 | +import { useRef, useState } from 'react'; |
| 30 | +
|
| 31 | +function AutoResizeTextarea() { |
| 32 | + const [text, setText] = useState(''); |
| 33 | + const textareaRef = useRef<HTMLTextAreaElement>(null); |
| 34 | +
|
| 35 | + // Auto-resize textarea based on content |
| 36 | + useAutosizeTextArea(textareaRef, text); |
| 37 | +
|
| 38 | + return ( |
| 39 | + <textarea |
| 40 | + ref={textareaRef} |
| 41 | + value={text} |
| 42 | + onChange={(e) => setText(e.target.value)} |
| 43 | + placeholder="Start typing... The textarea will auto-resize!" |
| 44 | + style={{ minHeight: '40px', resize: 'none' }} |
| 45 | + /> |
| 46 | + ); |
| 47 | +} |
| 48 | +``` |
| 49 | + |
| 50 | +## Usage with Initial Height |
| 51 | + |
| 52 | +```typescript |
| 53 | +import { useAutosizeTextArea } from '@/hooks/use-auto-resize-textarea'; |
| 54 | +import { useRef, useState } from 'react'; |
| 55 | +
|
| 56 | +function CommentBox() { |
| 57 | + const [comment, setComment] = useState(''); |
| 58 | + const textareaRef = useRef<HTMLTextAreaElement>(null); |
| 59 | +
|
| 60 | + // Set initial height and auto-resize |
| 61 | + useAutosizeTextArea(textareaRef, comment, '60px'); |
| 62 | +
|
| 63 | + return ( |
| 64 | + <div className="comment-box"> |
| 65 | + <textarea |
| 66 | + ref={textareaRef} |
| 67 | + value={comment} |
| 68 | + onChange={(e) => setComment(e.target.value)} |
| 69 | + placeholder="Write your comment..." |
| 70 | + className="w-full border rounded p-2" |
| 71 | + /> |
| 72 | + </div> |
| 73 | + ); |
| 74 | +} |
| 75 | +``` |
| 76 | + |
| 77 | +## Features |
| 78 | +- **Automatic resizing**: Adjusts height based on content |
| 79 | +- **Initial height support**: Can set a starting height before auto-sizing |
| 80 | +- **Performance optimized**: Only recalculates when value changes |
| 81 | +- **No external dependencies**: Uses native DOM properties |
| 82 | +- **Smooth resizing**: Provides smooth visual transitions |
| 83 | + |
| 84 | +## Implementation Details |
| 85 | +- **Trigger**: Runs whenever `value`, `textAreaRef`, or `initialHeight` changes |
| 86 | +- **Reset method**: Sets height to 'auto' or initial height first |
| 87 | +- **Calculation**: Uses `scrollHeight` property to determine required height |
| 88 | +- **Safety check**: Verifies textarea exists before attempting to resize |
| 89 | + |
| 90 | +## CSS Recommendations |
| 91 | + |
| 92 | +```css |
| 93 | +.auto-resize-textarea { |
| 94 | + resize: none; /* Disable manual resize */ |
| 95 | + overflow: hidden; /* Hide scrollbars */ |
| 96 | + min-height: 40px; /* Set minimum height */ |
| 97 | + transition: height 0.1s ease; /* Smooth height transitions */ |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +## Common Use Cases |
| 102 | +- **Comment boxes**: Auto-expanding comment inputs |
| 103 | +- **Message composition**: Chat message inputs that grow with content |
| 104 | +- **Note-taking**: Text areas for notes that expand as user types |
| 105 | +- **Form fields**: Multi-line form inputs with dynamic sizing |
| 106 | +- **Code editors**: Simple code input areas |
| 107 | +- **Rich text areas**: Foundation for rich text editors |
| 108 | + |
| 109 | +## Best Practices |
| 110 | +- Always set `resize: none` in CSS to prevent manual resizing conflicts |
| 111 | +- Set a reasonable `min-height` to prevent textarea from becoming too small |
| 112 | +- Consider setting a `max-height` with `overflow-y: auto` for very long content |
| 113 | +- Use with controlled components (useState) for proper value tracking |
| 114 | +- Test with various content types (short text, long paragraphs, line breaks) |
| 115 | + |
| 116 | +## Styling Tips |
| 117 | +```css |
| 118 | +/* Recommended base styles */ |
| 119 | +.autosize-textarea { |
| 120 | + resize: none; |
| 121 | + overflow: hidden; |
| 122 | + min-height: 2.5rem; |
| 123 | + max-height: 300px; /* Optional: prevent excessive height */ |
| 124 | + transition: height 0.15s ease; |
| 125 | + box-sizing: border-box; |
| 126 | +} |
| 127 | +
|
| 128 | +/* When max-height is reached, show scrollbar */ |
| 129 | +.autosize-textarea.max-height-reached { |
| 130 | + overflow-y: auto; |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +## Accessibility Considerations |
| 135 | +- Maintains all standard textarea accessibility features |
| 136 | +- Screen readers work normally with auto-resizing textareas |
| 137 | +- Focus behavior remains unchanged |
| 138 | +- Keyboard navigation is unaffected |
| 139 | + |
| 140 | +## Performance Notes |
| 141 | +- Very lightweight - no expensive calculations |
| 142 | +- Uses native DOM properties for optimal performance |
| 143 | +- Effect only runs when dependencies change |
| 144 | +- No polling or continuous monitoring required |
0 commit comments