feat(input-area): add auto resize support#625
Conversation
- No-op entirely when autoResize is off so a user's manual drag-resize is never clobbered by value changes; restore inline styles when the prop toggles off - Add maxRows: clamp growth via computed line-height and flip overflow-y to auto past the clamp so content stays scrollable - Account for box-sizing and borders when converting scrollHeight to an explicit height - Re-measure on inline-size changes via ResizeObserver so rewrapped content keeps the correct height - Avoid the React 18 SSR useLayoutEffect warning and honor React 19 callback-ref cleanups Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/bonk please review |
commit: |
Docs PreviewCommit: |
There was a problem hiding this comment.
Thanks for the thorough PR! The implementation is solid — useTextareaAutoResize correctly accounts for box-sizing, borders, and width-driven rewraps. The React 19 callback-ref cleanup and SSR-safe useIsomorphicLayoutEffect are nice touches.
A couple of suggestions and one minor concern:
Performance: handleChange calls resize() on every input event, and the layout effect calls it again after the subsequent render. For controlled inputs this causes two forced synchronous layouts per keystroke. Relying solely on the layout effect for controlled components would halve that work. You could detect control mode (e.g. 'value' in inputProps) and skip the handleChange resize when controlled, since the layout effect already covers post-render measurement.
Edge case: getComputedStyle will typically resolve line-height to a pixel value, but if a browser or testing environment returns a unitless string like "1.5", parsePx("1.5") yields 1.5 and maxHeight collapses to 1.5 * maxRows pixels, which would clamp far too aggressively. A small safety check like Number.isNaN(parsePx(style.lineHeight)) ? parsePx(style.fontSize) * 1.2 : parsePx(style.lineHeight) would make the fallback more explicit.
Tests: Great coverage for the main paths. Consider adding a test that unmounts an autoResize textarea and verifies style.height and style.overflowY are cleared (the cleanup is implemented but not asserted).
None of these are blockers — the feature works correctly as-is. Nice work.
|
Review submitted to PR #625. Summary: The auto-resize implementation is solid with good edge-case handling (box-sizing, borders, width rewraps, React 19 refs, SSR). I left two non-blocking inline suggestions:
Overall approved with comments — no blockers. |
…ht parsing - Skip the change-handler resize for controlled inputs; the post-render layout effect already re-measures, so this halves forced layouts per keystroke - Treat a unitless computed line-height (e.g. "1.5") as a font-size multiplier instead of pixels so the maxRows clamp stays correct - Add tests for unitless line-height and unmount style cleanup Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
/bonk I think I addressed your feedback! Please re-review |
There was a problem hiding this comment.
All prior feedback has been addressed. Re-approving.
- Performance:
handleChangenow guardsresize()with!isControlled, eliminating the double forced synchronous layout per keystroke for controlled inputs. - Edge case:
line-heightparsing now correctly treats unitless values (e.g.'1.5') as font-size multipliers instead of raw pixels, and falls back tofontSize * 1.2for'normal'. - Tests: Added the unmount cleanup assertion verifying
style.heightandstyle.overflowYare cleared.
No blockers — nice work!
|
Re-reviewed and approved ✅ All three items from the prior review were addressed:
|






Summary
Adds an optional
autoResizeprop toInputAreaand itsTextareaalias. When enabled, the textarea grows vertically with its content.Changes
onChange,onValueChange, and forwarded ref behavior@cloudflare/kumoImplementation note
field-sizing: contentwas considered, but it can also change the textarea’s inline size. SinceautoResizeis intended to affect only vertical height, this implementation usesscrollHeightinstead. This also avoids relying onfield-sizingsupport in older browsers.Testing
CI=true pnpm --filter @cloudflare/kumo exec vitest run --project=unit src/components/input/input.test.tsxpnpm --filter @cloudflare/kumo typecheckpnpm --filter @cloudflare/kumo lint