Skip to content

[Bug]: iOS composer requires tapping outside text box before Send works on follow-up messages #11755

Description

@iniTwakkie

Area

apps/mobile

Steps to reproduce

  1. Open a thread in the T3 Code iOS companion app (or start a task from mobile).
  2. Wait for the initial response from the agent so the transcript / message feed is populated.
  3. Tap the chat composer text input to bring up the iOS keyboard and type a follow-up message.
  4. While the keyboard is active and the text input remains focused, tap the Send button (arrow up).
    • The message is not sent.
  5. Tap outside the message input box (into the transcript feed), dismissing the keyboard and blurring the composer.
  6. Tap the Send button again.
    • The message sends as expected.

(Note: On the initial task draft screen, typing a message and immediately tapping Send works on the first tap without this issue.)

Actual behavior

Tapping the Send button while the composer text input is focused does not dispatch the message. The tap is swallowed / consumed by the blur/dismiss gesture, collapsing the composer or dismissing the keyboard without triggering the send action. The user must tap outside the text box first to dismiss the keyboard, and only then does the Send button respond to taps.

Expected behavior

Tapping the Send button while typing should immediately dispatch the message on the first tap, without requiring the user to blur the input beforehand.

Workaround

Tap anywhere outside the composer input box into the transcript feed to dismiss the keyboard and blur the composer first, then tap the Send button.

Supporting investigation

Source inspection of apps/mobile:

  • In ThreadDetailScreen.tsx, the feed is wrapped with touch gesture handlers (BlurTargetView with onTouchStart / onTouchEnd triggering collapseComposer()), and LegendList is configured with keyboardDismissMode="none".
  • In ThreadComposer.tsx, when typing, the composer is in an expanded state (isExpanded = true) within KeyboardStickyView. When the Send button is tapped while the native text editor is the active first responder, the tap event triggers input blur and layout transitions (COMPOSER_LAYOUT_TRANSITION) before ComposerActionButton's onPress callback can fire.
  • In contrast, NewTaskDraftScreen.tsx (where the initial message works on first tap) does not render the active ThreadFeed / LegendList touch responder overlay behind the composer.

Environment

  • Platform: iOS
  • App: T3 Code Mobile Companion (React Native / Expo)

Activity

  1. juliusmarminge commented on Sep 14, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed as a real iOS thread-composer send bug. Tapping Send while the editor is focused does not dispatch the follow-up; the first tap blurs/collapses, and only a later tap (after dismissing the keyboard) sends. The new-task draft screen sending on the first tap is a useful contrast, not a contradiction.

    This is not a duplicate of #7390 (send stays disabled / draft bleed), #10956 (focus lost after skill pick), or #7440 (composer sits behind the keyboard during hydration). Same class as #10956 (blur collapses the card) but a different trigger. No open/merged PR fixes Send being swallowed while the thread composer is focused.

    What’s going on

    Thread composer (apps/mobile)

    • ThreadComposer keys the card on focus: isExpanded = isFocused || settingsSheetPresentation.keepsComposerExpanded.
    • While typing, Send lives on the expanded toolbar (ComposerActionButton + onPress={handleSend}).
    • Tapping Send is outside the native UITextView. iOS resigns first responder (textViewDidEndEditing → onComposerBlur → handleBlur) before RN onPress can fire.
    • Blur flips isExpanded off, unmounts that Send (pointerEvents="none" on the toolbar), mounts the compact Send in a different slot, and runs COMPOSER_LAYOUT_TRANSITION (220ms, iOS only). onPress needs touch-up on the same view, so the gesture dies.

    Feed overlay

    • ThreadDetailScreen wraps the feed in BlurTargetView with onTouchStart / onTouchEnd → collapseComposer() → editor.blur().
    • ThreadFeed already uses keyboardShouldPersistTaps="always" and keyboardDismissMode="none". A miss or stale Reanimated hit target (see #11114) can take the tap as “tap the transcript” and only dismiss.

    Why new task works

    • NewTaskDraftScreen uses the same Send button and KeyboardStickyView, but it does not morph compact/expanded on focus. Blur does not remount Send, so the first tap lands.

    Web already had to stop collapsing on composer-chrome taps (#9490). Mobile thread composer still treats any editor blur as “collapse the card,” including a tap on Send.

    Suggested fix

    1. Do not remount/disable the expanded Send on the same gesture that hits it (onPressIn, delay collapse until after press, or keep expanded across chrome taps).
    2. Keep feed collapseComposer() off composer chrome (exclude overlay bounds / don’t let those touches fall through).
    3. Device-check: focused follow-up Send, Stop while focused, model/attachment with keyboard up, new-task first send unchanged. Android unverified.

    Severity: medium–high (extra tap on every iOS follow-up).

    Accepting this. Localized to the thread composer + feed overlay; new-task is the working control.

  2. added
    bugSomething is broken or behaving incorrectly.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 14, 2026
  3. iniTwakkie commented on Sep 14, 2026

    @iniTwakkie
    Author

    Device details for reproduction:

    • Device: iPhone 13 Pro Max
    • OS Version: iOS 26.6.2
  4. juliusmarminge commented on Sep 15, 2026

    @juliusmarminge
    Member

    Not reproducable on latest Testflight. Hope to ahve a new app store release in the next day or two

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions