Skip to content

[Bug]: Programmatic scrolls still glide when Reduce Motion is on (web and iOS) #15953

Closed

Description

@saphid

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/web, apps/mobile (desktop runs the web client)

Steps to reproduce

Web / desktop

  1. Turn on Reduce Motion (macOS: System Settings → Accessibility → Display → Reduce motion; or emulate prefers-reduced-motion: reduce in Chrome DevTools).
  2. Open a thread long enough to scroll, scroll up, and click Scroll to end.
  3. With the composer focused and the timeline scrolled up, press PageDown.
  4. Click a turn in the timeline minimap (the strip in the left gutter, or its next/previous buttons).
  5. Settings → Appearance → duplicate a theme → Inspect, then click an app element whose color row is out of view in the editor.

iOS

  1. Settings → Accessibility → Motion → Reduce Motion on.
  2. Open a long thread, scroll up, tap Scroll to end.
  3. Scroll up, type a message, send it.

Expected behavior

With Reduce Motion on, these programmatic scrolls jump straight to their destination. Normal motion is unchanged when the setting is off. Several web paths already do this (tab-strip scrolling, settings search reveal, citation reveal, streaming end-follow).

Actual behavior

Each of these still animates, whatever the setting says.

Measured on main a1d9d72aef. Web: headless Chrome for Testing, real prefers-reduced-motion emulation, per-frame scrollTop sampling. Counts are frames strictly between the start and end positions.

Action Reduce Motion on Off
Scroll to end (5479 px) 72 frames 72
PageDown from composer (602 px) 9 8
Minimap jump (392 px) 18 18
Theme editor inspect reveal (48 px) 4 positions 7

iOS 26.5 simulator with the real Settings toggle: Scroll to end glides through the whole thread (19 significant frame changes). After sending, the new message glides up as the keyboard closes.

Code: apps/web/src/components/ChatView.tsx (scrollToEnd), apps/web/src/components/chat/pageScrollController.ts (smoothScrollBy), apps/web/src/components/chat/MessagesTimeline.tsx (minimap onSelect), apps/web/src/components/settings/ThemeEditorPanel.tsx (selectThemeRole), apps/mobile/src/features/threads/ThreadDetailScreen.tsx (scrollMessageToEnd({ animated: true }) in the send effect and handleScrollToEnd).

Impact

Minor bug or occasional failure. It affects every user who relies on Reduce Motion, usually because motion makes them unwell.

Version or commit

main @ a1d9d72

Environment

macOS 26 host; Chrome for Testing (Playwright 1.60, chromium-1243) with media emulation; iOS 26.5 simulator (iPhone 17 Pro) running T3 Code Dev built from main; Codex provider for the test turns.

Screenshots, recordings, or supporting files

Not verified: the macOS desktop app with the real system setting (the web client was checked in Chrome with media emulation; Electron uses the same matchMedia query), and Android.

Workaround

None.

Context: closed PR #12871 targeted this; it was closed for missing live motion proof. This report gives that proof on current main.

Activity

  1. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks @saphid for the thorough report. The frame counts, recordings, and simulator runs with the real setting make this easy to follow. Current main (250e052f44) matches what you describe, and nothing since a1d9d72aef has touched these scroll paths.

    What I found

    Each of these call sites always animates, whatever the setting:

    • Scroll to end (apps/web/src/components/ChatView.tsx): the button calls scrollToEnd(true), which passes animated through to legendListRef.scrollToEnd.
    • PageDown (apps/web/src/components/chat/pageScrollController.ts): the single step always runs smoothScrollBy, a 150 ms eased requestAnimationFrame loop.
    • Minimap (apps/web/src/components/chat/MessagesTimeline.tsx): onSelect calls scrollToIndex({ animated: true }).
    • Theme inspect (apps/web/src/components/settings/ThemeEditorPanel.tsx): selectThemeRole calls scrollIntoView({ behavior: "smooth" }).
    • iOS send and Scroll to end (apps/mobile/src/features/threads/ThreadDetailScreen.tsx): both call scrollMessageToEnd({ animated: true }).

    Streaming end-follow, citation reveal, settings search, and the right panel tab strip already jump when (prefers-reduced-motion: reduce) matches.

    Two more paths may be worth covering in the same fix:

    • Sending on web also animates. onTimelineAnchorReady calls scrollToIndex({ animated: true }), and that path isn't in the measurement table.
    • Holding PageUp or PageDown keeps scrolling while the key is down. The report measures the single PageDown step.

    Android, and the macOS desktop app with the real system setting, are still unchecked. The desktop app runs this same web client and uses the same matchMedia query.

    Likely fix area

    One option is to make each of these call sites check the existing reduced-motion preference and jump instead of animating, the way the paths above already do. Another is a small shared helper for programmatic scrolls on web and on mobile. The broader reduced-motion contract proposed in #12660 is a separate question.

    A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 5, 2026
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