-
Notifications
You must be signed in to change notification settings - Fork 4k
[feat] Add dynamic layout switching for st.chat_input
#13546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] Add dynamic layout switching for st.chat_input
#13546
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
1f97bec to
30542a4
Compare
01add8e to
1d41a1c
Compare
30542a4 to
c499bc6
Compare
1d41a1c to
b42d84f
Compare
c499bc6 to
adb9c8f
Compare
c644a77 to
79baf6a
Compare
08b362e to
558aa1f
Compare
79baf6a to
9d06611
Compare
558aa1f to
c672a13
Compare
9d06611 to
8e88e79
Compare
8e88e79 to
b4f3438
Compare
e4fc286 to
01bbe71
Compare
| return | ||
| } | ||
|
|
||
| // Small delay to allow textarea to mount and get proper dimensions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: There isn't a guarantee that this the chat input ref will exist after 1 microtask (what this setTimeout is attempting to solve for). You may be able to fix this by make the ref a callback function, which would guarantee that it exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call on the timing issue. I tried the callback ref approach but TextArea only accepts RefObject for inputRef, not callback refs. :(
Ended up using useLayoutEffect instead since it runs synchronously after DOM mutations so the ref is guaranteed to be set. Removed the setTimeout entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah maybe I spoke too soon, I think this broke the case I was trying to fix here :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nvm, I think we good now.
Implements ChatGPT-style dynamic layout switching for chat input: - Starts in inline mode: [+] [textarea flex:1] [mic] [send] - Switches to stacked mode when text fills available width: - Full-width textarea on top row - Buttons row below with + on left, mic/send on right Key changes: - Add isStacked state to track layout mode - Use canvas text measurement to detect when text fills width - Refocus textarea and restore cursor position on mode transition - Unified layout structure for both modes (removes old simple/extended split)
…ew one per keystroke
- Simplify refocus effect to always restore focus after layout transition (layout only changes due to user typing, so they always have focus) - Remove unnecessary value dependency from refocus effect - Add canvas ref cleanup on unmount for garbage collection - Improve E2E test efficiency by using fill() instead of loop-based backspace - Add negative assertion to verify short text stays in inline mode
Track previous isStacked value to detect actual layout transitions instead of just checking mount state. This prevents the textarea from stealing focus when the page initially loads.
- Use flexbox align-items: center for proper vertical alignment - Reduce container padding to md (12px) for 58px total height - Reduce textarea padding to twoXS (4px) - Add alignItems: center to inline textarea wrapper - Fix auto-focus on page load by tracking actual layout transitions
Instead of rendering UITextArea in different DOM positions (which causes remount and focus loss), keep it at a fixed position and use CSS flex properties (order, width, flex-wrap) to visually move it above buttons when in stacked mode. This eliminates the need for manual focus/cursor restoration after layout transitions.
- Fix textarea alignment after audio recording/submission by using height: auto when not in extended mode - Re-measure textarea width when recording ends to ensure stacked layout detection works correctly after audio submission - Add e2e tests for layout alignment and stacking after audio events
- Move waveform inline with cancel/approve buttons during recording - Adjust waveform height to match button size for consistent layout - Add type=button to file upload button to fix click handling
Use useLayoutEffect instead of setTimeout to measure textarea dimensions. This provides deterministic timing as useLayoutEffect runs synchronously after DOM mutations, guaranteeing the ref exists when we measure.
468d892 to
c3d8430
Compare

Describe your changes
Improved the ChatInput component to dynamically switch between inline and stacked layouts based on content length. The component now:
This creates a more responsive experience that adapts to the user's input without jarring layout shifts.
Screenshot or video (only for visual changes)
Testing Plan
st_chat_input_test.pythat verify the dynamic layout transitionsContribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.