Skip to content

[Bug]: Android inline HTML traps chat scrolling when its content overflows #16989

Description

@dylan1020

Summary

In the native Android app, an overflowing inline HTML page captures vertical swipes that should let the reader continue through the conversation. Swipes starting inside the HTML do not move the chat, including when the page cannot scroll farther in that direction. Swiping the narrow gutter beside the page moves the chat normally. A large HTML page can occupy almost the entire chat viewport, making the conversation feel locked.

The original report is from a Pixel 10 Fold with no known increase in system text or display size. The same HTML reproduced the problem in a Pixel 10 Pro Fold emulator at a forced 320dp layout width. It did not reproduce at the emulator's default width of about 443dp. The reproduction confirms the gesture trap, but does not yet establish why the original phone reaches the overflow condition at its normal settings.

Area

apps/mobile / Android / inline HTML in the thread feed.

Steps to reproduce

  1. Open a native Android development client connected to an isolated T3 Code environment.
  2. Extract original.html and render-metadata.json from the attached reproduction archive. Render the HTML as an inline HTML tool result, with ordinary assistant text following it. The original result used a height of 582 and the responsive heights in the metadata file.
  3. Use a narrow layout where the HTML overflows its inline frame. The tested emulator used a 1080px-wide folded display, density 540, and font scale 1.0, giving a 320dp screen width and approximately 288dp of HTML content width. On this emulator, adb shell wm density 540 produced that layout; adb shell wm density reset restores its default density.
  4. Position the conversation so the lower part of the HTML and the following assistant text are visible.
  5. Swipe downward starting inside the HTML, toward earlier conversation content. Observe that the following assistant text does not move.
  6. Repeat the downward swipe starting in the left gutter outside the HTML. Observe that the conversation moves.

Also try the case where the HTML fills the available chat viewport, shown below. The usable gutter becomes easy to miss.

Expected behavior

Vertical swipes over inline HTML should allow conversation scrolling when the embedded page cannot consume the movement, including at its scroll boundaries. Readers should be able to move past a large inline page without finding a narrow gutter.

Actual behavior

The HTML keeps the gesture and the parent chat stays still. A gutter swipe immediately moves the conversation.

A controlled test measured the vertical position of the same assistant text before and after a 250px downward pan:

Native WebView setting Pan inside HTML: chat movement Pan in gutter: chat movement
Original source 0px 249px
Only nestedScrollEnabled temporarily set to false 241px 249px
Original source restored 0px 249px

The recording used longer, 450px pans and showed the same behavior: 0px of chat movement inside the HTML, then 487px from the gutter. The temporary probe was reverted. No fix has been made.

Screenshots and recording

Play the recording (MP4, about 23 seconds).

The conversation stays in the same position during the inside-HTML swipe in the first part of the recording. Around 16–19 seconds, a gutter swipe moves it. The final gutter swipe returns it to the starting position. Gesture locations are described here because the recording does not display a touch pointer.

After the inside-HTML swipe: the following assistant text remains in place.

Chat unchanged after swiping inside the HTML

After the gutter swipe: the following assistant text has moved downward and earlier table content is visible.

Chat moves after swiping the gutter

Large-page case: the HTML occupies nearly the whole chat viewport.

Inline HTML fills the available chat viewport

Default-width screenshot, where this HTML scrolled normally.

Likely cause

HtmlRenderWebView.tsx reports either vertical or horizontal overflow. Overflow enables scrollEnabled and nestedScrollEnabled for the inline WebView.

In the installed react-native-webview 14.0.1 Android implementation, RNCWebView.onTouchEvent calls requestDisallowInterceptTouchEvent(true) whenever nestedScrollEnabled is enabled. This prevents the parent from taking the gesture even at a scroll boundary. Horizontal-only overflow can also enable this behavior for vertical swipes.

The attached HTML consists of two static tables and contains no scripts or touch-event handlers. The one-variable probe above supports WebView gesture interception as the cause. Disabling nested scrolling was a diagnostic probe; a fix still needs to preserve useful interaction with overflowing HTML.

Impact and workaround

Major degradation when a large inline page fills the chat viewport. Swipe the side gutter outside the HTML to move the conversation.

Version and environment

  • Tested source commit: 26285ab80513260d1ff29d2c3fbe18f21990cb62.
  • Native Android development client; mobile app config version 2.0.0.
  • Pixel 10 Pro Fold emulator, Android API 36, folded display 1080 × 2364px.
  • Reproducing layout: density 540, screen width 320dp, system font scale 1.0.
  • Default emulator density 390 did not reproduce with this HTML.
  • Reported physical device: Pixel 10 Fold; exact installed app version and physical-device display metrics are not yet recorded.
  • Test data was copied into an isolated environment. No live conversation state was modified.

The Linux native build initially packaged a host Oniguruma library. A disposable APK was repaired to use the dependency's Android library and re-signed for testing. The baseline HTML component and WebView dependency were unchanged. This evidence is from a development build, not a verified reproduction on the Play Store build.

Existing reports

Searches of public issues, recent discussions, and the inline HTML feature's review comments did not find an exact duplicate. Issue #13925: Android scrolling a long, settled thread is janky concerns a related scrolling symptom, with a different reported cause involving text mounting in long threads.

Follow-up

If this issue is marked Approved or Verified, we can implement a fix and open a pull request for review.

Activity

  1. juliusmarminge commented on Oct 7, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Thanks for the careful write-up and the one-variable probe. I checked it against current main (3143335). Your tested commit 26285ab is 7 commits behind main, and HtmlRenderWebView.tsx hasn't changed since the inline HTML feature landed (#15968).

    Confirmed in code, not reproduced here. I didn't run the app or open the attached archive or recording.

    Why the gesture gets trapped

    • In the feed, the WebView reports whether the page overflows its frame. The overflow script flags overflow when the page is taller or wider than the window. Once it reports overflow, scrollable turns on both scrollEnabled and nestedScrollEnabled:
      const scrollable = !props.nested || overflows;
      scrollEnabled={scrollable}
      nestedScrollEnabled={props.nested && overflows}
    • Main pins react-native-webview at 14.0.1 (apps/mobile/package.json and the lockfile), and the repo doesn't patch it. In that version, RNCWebView.onTouchEvent calls requestDisallowInterceptTouchEvent(true) on every touch whenever nestedScrollEnabled is set. It doesn't check direction or whether the page is at a scroll edge. That call tells ancestor views not to intercept the gesture, so once overflow is reported, a vertical swipe that starts on the page never reaches the feed's list, even at the page's top or bottom.
    • Because the overflow check also counts horizontal overflow, a page that's only too wide (for example a wide table) gets the same treatment, and vertical swipes on it are trapped too.
    • The feed is a KeyboardAwareLegendList that renders ThreadHtmlRender rows. Neither the row nor HtmlRenderWebView has any gesture handling that would pass the swipe back at the edges.

    This matches your probe: turning off only nestedScrollEnabled let swipes on the page move the chat.

    Why it overflows at 320dp and not at about 443dp (what the code shows)

    • The frame is a fixed height from htmlRenderFrameHeight(render, frameWidth), and the same value sizes the row (ThreadFeed.tsx#L2931). Mobile passes no page-reported height, so the frame comes only from the server's publish-time measurements, or the agent's height when there are none.
    • frameWidth is the viewport minus the feed's padding, at least 16dp per side outside the split layout (ThreadFeed.tsx#L2257-L2263). A 320dp screen gives 288, which matches your ~288dp.
    • The server measures at widths starting at 320. For a width below 320, measuredHeight falls back to the 320 measurement. A page that wraps taller (or doesn't fit horizontally) at 288 than at 320 then overflows its frame. At about 443dp the frame is around 411 wide, which lies between the measured 375 and 430 widths, and the frame takes the taller of those two heights.
    • Separately, htmlRenderFrameHeight caps the frame at the agent's height (582 here) when the page measured taller than that at the 728 column width. Pages over the 2000px max are capped as well. Either case gives an intentionally scrolling frame at any width.
    • I haven't checked which of these applies to your page. That needs the page's metadata, and I didn't open the archive. It also doesn't explain the physical Pixel 10 Fold at default settings, which (as you note) is still open.

    Fix options (not choosing one here)

    1. Hand the gesture back at the edges and by direction. Only keep the touch while the page can still scroll in the swipe's direction. That could be native (a patch or a subclass that calls requestDisallowInterceptTouchEvent conditionally) or driven from JS using the page's scroll position. It keeps scrollable inline pages.
    2. Split vertical and horizontal overflow. Don't enable nested scrolling for vertical swipes when the page only overflows horizontally.
    3. Avoid unintended overflow. Measure at a width below 320, or pass the page's reported height on mobile as web does, so pages that are meant to fit actually fit.
    4. Don't nest-scroll inline at all. For example, only scroll after the reader taps or focuses the page, or show a non-scrolling preview and use the existing open-full-screen button for scrolling. This one is a product/UX call.

    Options 1–3 fix code behavior. Option 4 is the same question as #16977.

    Workaround: as you found, swipe in the gutter beside the page, or open the page full screen with the expand button.

    Related

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 7, 2026
  3. juliusmarminge commented on Oct 8, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    This is fixed by #17211, which just landed on main. On Android, overflowing inline HTML pages now hand vertical swipes back to the thread once the page can't scroll further in that direction, and pages that only overflow horizontally no longer hold vertical drags. Closing as completed. If you still see the trap on a build that includes #17211, please reopen with details.

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

    bugSomething 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