How does the textarea auto resize work?
how does the textarea auto resize work?
In apps/web/components/composer.tsx, the textarea is auto-resized manually with a ref and an onChange handler.
Core pieces:
const textareaRef = useRef<HTMLTextAreaElement>(null)
const [isScrollable, setIsScrollable] = useState(false)
The resize logic is here:
const adjustTextareaHeight = useCallback(() => {
const textarea = textareaRef.current
if (!textarea) {
return
}
textarea.style.height = "auto"
const maxHeight = 264 - 48 // 264px total max - ~48px footer
const newHeight = Math.min(textarea.scrollHeight, maxHeight)
textarea.style.height = `${newHeight}px`
setIsScrollable(textarea.scrollHeight > maxHeight)
}, [])
How it works:
-
It grabs the DOM node through
textareaRef. -
It first sets
textarea.style.height = "auto"
This is important because it allows the textarea to shrink when text is deleted. Without this, it would only grow. -
It reads
textarea.scrollHeight, which is the full height needed to fit the content. -
It caps the height at:
const maxHeight = 264 - 48So the textarea itself maxes out around
216px, leaving room for the composer footer/buttons. -
It applies the new height:
textarea.style.height = `${newHeight}px` -
If the content is taller than the max, it sets:
setIsScrollable(true)At that point the textarea stays capped and becomes internally scrollable.
The function runs whenever the textarea changes:
onChange={(e) => {
const value = e.target.value
if (value) {
sessionStorage.setItem(storageKey, value)
} else {
sessionStorage.removeItem(storageKey)
}
adjustTextareaHeight()
onChange?.(value)
}}
It also runs when restoring a saved draft from sessionStorage:
useEffect(() => {
const saved = sessionStorage.getItem(storageKey)
if (saved && textareaRef.current) {
textareaRef.current.value = saved
adjustTextareaHeight()
}
onChange?.(saved || "")
}, [storageKey, adjustTextareaHeight, onChange])
And after successful submit, it resets back to the default height:
form.reset()
sessionStorage.removeItem(storageKey)
if (textareaRef.current) {
textareaRef.current.style.height = "auto"
}
setIsScrollable(false)
The textarea itself also has resize-none, so users cannot manually resize it:
className="no-focus min-h-27 w-full resize-none ..."
So in short: it is an uncontrolled textarea managed through a DOM ref. On each change, the code resets the height, measures scrollHeight, applies the smaller of scrollHeight and the max height, and toggles scroll styling once the content exceeds that cap.
END OF POST