Skip to content

Mobile Chat UI: transcript scrolls away and back ~1s after each send (tail pin fights maintainVisibleContentPosition) #31979

Closed

Description

@letjsk

Setup: Orca Mobile against a headless orca serve 1.4.237 host (Linux x64), mobile web bundle buildId dd9bb94d35f0fbe8c2deca2534f0833cac75e43516c9f5999c5c6de02c2f209a, desktopVersion 1.4.237, installed 2026-10-21 20:17. Claude Code 2.1.308, chat surface (not the terminal view). Started after that update.

Observed: send a message in the mobile Chat UI and about 1–2 seconds later the whole transcript jumps — it scrolls up and then settles back to where it was. Nothing is lost or reordered; only the scroll position moves, once per send. It reads as a flicker of the chat view.

Steps to reproduce

  1. Open a Claude Code session in the mobile Chat UI.
  2. Send a message.
  3. Watch the list about a second after the send, as the reply starts.

Expected: the transcript stays put (or stays pinned to the bottom) while a pending message is replaced by its confirmed row.

Actual: the list visibly scrolls away and comes back.

Where I think it comes from — code reading of the shipped bundle, not a measured trace (out/mobile-web/assets/3b3d6729…js):

The chat list is configured with two scroll stabilizers at once:

onContentSizeChange: t.pinToTailAfterContentResize,
onLayout:            t.pinToTail,
maintainVisibleContentPosition: aL(e.hasHeader),

and the same component merges optimistic sends with confirmed transcript rows:

{ optimistic: useMemo(() => g.filter(v => !v.unconfirmed), [g]) }
hV(H, Y.optimistic, w.submissions, yV)

So roughly a second after the send, the optimistic bubble is swapped for the confirmed row and the content height changes. maintainVisibleContentPosition holds the previously visible anchor (shifting the viewport) while pinToTailAfterContentResize pulls back to the tail on the same content-size change. The two corrections fire against each other, which matches the "scrolls up, then returns" shape and the 1–2 second delay.

Ask: pick one owner for the scroll position during the optimistic → confirmed swap — either keep maintainVisibleContentPosition and drop the tail pin for that update, or suppress the anchor while the list is pinned to the bottom, so a row replacement of equal intent does not move the viewport.

Possibly related: #25905 (mobile auto-scroll to latest is slow / gets stuck), #31177, and the optimistic-echo handling discussed in #18852 / #14308.

Activity

  1. AmoabaKelvin commented on Oct 31, 2026

    @AmoabaKelvin
    Collaborator

    Thanks for the detailed report. This no longer reproduces on current main: the mobile chat page was rewritten to anchor at the bottom (#31339, #33664), so swapping the pending bubble for the confirmed message can't move the view. We checked against real Claude on Android and iOS with a per-frame recorder across several sends and saw no jump. Closing as fixed; please reopen if you still see it on a current desktop host.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions