[BUG] Forces scroll to top when outputting code (NOT just when scrolling)

Resolved 💬 35 comments Opened Mar 13, 2026 by loekj Closed Apr 26, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Whenever I'm trying to read what Claude's doing, so I have my scroll position somewhere not at bottom or top; and then Claude forces my scroll position to top (it jumps) out of nowhere, whenever it's outputting code.
This was a bug in old versions, and somehow it's back. Massive annoying regression.
CC version 2.1.74
MacOS Tahoe 26.4
MacBook Pro M4 Pro
iTerm2 3.6.8

PS:
All the other bug reports indicate WHEN SCROLLING UP, but I'm just trying to read in place.

What Should Happen?

It should just let me read.

Error Messages/Logs

Steps to Reproduce

  1. Just have it output lots of code.
  2. Go somewhere in the terminal for reading
  3. See it jump
  4. Throw your cat out of the window

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

Unsure, but 2.1.69 maybe?

Claude Code Version

2.1.74

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

I have a .mov screen recording, but can't seem to upload here 🤷

<!-- Failed to upload "ARGH.mov" -->

View original on GitHub ↗

35 Comments

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/826
  2. https://github.com/anthropics/claude-code/issues/33367
  3. https://github.com/anthropics/claude-code/issues/33719

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

loekj · 4 months ago

PLEASE fix this ASAP. I can't read anything Claude does whenever it's still running. So annoying, I've defenestrated multiple cats already.

VoxCore84 · 4 months ago

We hit this too and collected working workarounds into a repo: claude-code-scroll-fix

Quick fix (Windows Terminal): Add "snapOnOutput": false to your profiles.defaults in settings.json. Reduces jumping ~60-70%.

Complete fix: Run Claude inside tmux — it completely decouples your scroll position from Claude's cursor repositioning. The repo has a one-click installer that sets up WSL + tmux + a Windows Terminal profile.

Root cause: Claude Code uses CSI escape sequences to rewrite the thinking spinner in-place, and terminals follow the cursor position back up. snapOnOutput only fixes output-triggered scrolling, not cursor repositioning — tmux fixes both.

loekj · 4 months ago
We hit this too and collected working workarounds into a repo: claude-code-scroll-fix Quick fix (Windows Terminal): Add "snapOnOutput": false to your profiles.defaults in settings.json. Reduces jumping ~60-70%. Complete fix: Run Claude inside tmux — it completely decouples your scroll position from Claude's cursor repositioning. The repo has a one-click installer that sets up WSL + tmux + a Windows Terminal profile. Root cause: Claude Code uses CSI escape sequences to rewrite the thinking spinner in-place, and terminals follow the cursor position back up. snapOnOutput only fixes output-triggered scrolling, not cursor repositioning — tmux fixes both.

Meh. Thanks, but Anthropic just has to fix this...

cruzlauroiii · 4 months ago

Root cause traced in cli.js v2.1.76 source: Ink's rendering uses \ on every re-render. When output is large, the cursor moves far up in the buffer and Windows Terminal (and iTerm) follows the cursor, snapping the viewport to the top. Full analysis in #34794.

cruzlauroiii · 4 months ago

Updated PR #34798 with v2 fix: stateful stdout.write interceptor that clamps cursor-up across ALL writes (not just sync blocks). Catches Ink renderer, prompt renderer, and all other cursor-up sources. Patch + PowerShell script included.

cruzlauroiii · 4 months ago

Updated PR #34798 with 3 combined patches: (1) stateful stdout.write interceptor clamping cursor-up, (2) render throttle 16ms→200ms, (3) disable synchronized update mode. All three are needed — cursor-up clamping alone does not fix it because Windows Terminal exits scroll mode on ANY stdout write, and sync blocks batch writes into one viewport-resetting update. PowerShell apply/revert script included.

cruzlauroiii · 4 months ago

v3 update: Previous fixes (cursor-up clamping, disabling sync update) did not work and caused flickering.

Root cause identified: Windows Terminal bug microsoft/terminal#14774SetConsoleCursorPosition always scrolls viewport to cursor, even when visible. Every Ink re-render triggers this. Cannot be fixed from within the process.

v3 patch: render throttle SK6=16SK6=1000 (1fps). Gives 1 second of uninterrupted reading between viewport resets. Trade-off: streaming text in ~1s chunks. No flickering.

PR #34798 updated. Real fix needs Microsoft (terminal#14774) or Anthropic (PTY proxy/append-only rendering).

cruzlauroiii · 4 months ago

v5 update: Fundamentally different approach — buffer ALL Ink renders during active work, screen stays frozen (no viewport jumping). Flush only when (a) user types (at prompt/bottom, safe to update) or (b) 5s of no renders (Claude finished). Previous v1-v4 failed because WT bug microsoft/terminal#14774 triggers viewport scroll on ANY cursor positioning. v5 avoids this by not writing to stdout at all during active work. Trade-off: no spinner/progress visible during work. PR #34798 updated.

cruzlauroiii · 4 months ago

v6: Buffer ALL renders, flush ONLY on user input (stdin). No timer. No auto-flush. Zero viewport jumping while not at bottom. Root cause: WT bug microsoft/terminal#14774. PR #34798.

cruzlauroiii · 4 months ago

v7: Replay ALL buffered frames on flush (fixes v6 outdated screens). Keeps entire diff chain so screen content is always correct. Still zero viewport jumping — flush only on user input (stdin). PR #34798.

cruzlauroiii · 4 months ago

Final fix: Ctrl+6 freeze toggle. Press Ctrl+6 to freeze screen (buffer renders, scroll freely). Press again to unfreeze (replay + live output). Tab title shows [FROZEN]. Root cause is WT bug microsoft/terminal#14774 — cannot be detected/fixed automatically. PR #34798.

loekj · 4 months ago
Final fix: Ctrl+6 freeze toggle. Press Ctrl+6 to freeze screen (buffer renders, scroll freely). Press again to unfreeze (replay + live output). Tab title shows [FROZEN]. Root cause is WT bug microsoft/terminal#14774 — cannot be detected/fixed automatically. PR #34798.

Thanks but it was fixed before, in a previous version. This is a regression, and I don't understand why not more people are absolutely going apeshit over this. It's the most annoying thing!
I can't do any work at any speed at the moment. I need to understand what's happening and currently am just waiting for it to wait to then read. Very annoying.

Gerk · 4 months ago

Same issue here — iTerm2 on macOS, Max account. This is a show-stopper. Viewport jumps to top of scrollback on every output event, making it impossible to read, select, or copy previous output. Have to scroll down thousands of lines to get back. Competing CLI tools do not have this problem in the same terminal. Will cancel Max subscription if this isn't fixed.

cruzlauroiii · 4 months ago

A fix for this is available as a Claude Code plugin: https://github.com/anthropics/claude-code/pull/35683

The scroll-fix plugin clamps cursor-up sequences within synchronized output blocks to the viewport height, preventing the terminal from scrolling to the top. Also includes Ctrl+6 freeze toggle for manual scroll control. Works on all platforms and terminals.

PerplexedPeach · 4 months ago

Is the intended solution for affected users a plugin? That seems completely unacceptable.

cruzlauroiii · 4 months ago

A fix is available as a Claude Code plugin: scroll-fix

Install:

/plugin marketplace add cruzlauroiii/claude-code
/plugin install scroll-fix@cruzlauroiii-plugins

Root cause: both Ink renderer AND readline/prompt system emit cursor-up sequences exceeding viewport height. The plugin clamps all cursor-up per write call. Also includes Ctrl+6 freeze toggle.

PR: https://github.com/anthropics/claude-code/pull/35683

1nu · 3 months ago

Eagerly awaiting for a resolution (that doesn't require and external plugin) for this very annoying bug.

mnaoumov · 3 months ago

@cruzlauroiii

/plugin marketplace add cruzlauroiii/claude-code
Error: The name 'claude-code-plugins' is reserved for official Anthropic marketplaces.
Only repositories from 'github.com/anthropics/' can use this name.   
shufog1 · 3 months ago

A simple workaround for this is to just type any letter in the session (don't send it)

james0r · 3 months ago

This is super aggravating.

loekj · 3 months ago
A simple workaround for this is to just type any letter in the session (don't send it)

Doesn't work on all terminals unfortunately

james0r · 3 months ago

Is this fix coming in the next version? Patch looks a little involved but
great work!

On Sat, Mar 21, 2026 at 11:21 AM dotiallwrong @.***>
wrote:

doitallwrong left a comment (anthropics/claude-code#33814) <https://github.com/anthropics/claude-code/issues/33814#issuecomment-4103894334> Hit this bug on Windows Terminal — viewport jumping to top while Claude is generating output, impossible to read anything. Decompiled cli.js, found the three functions responsible, patched them, tested. Scroll is stable now. ------------------------------ TL;DR — Problem: Three functions (HF7, v_.eraseLines, T_.eraseLines) generate cursor-up ANSI sequences (\x1b[nA) without clamping n to the terminal viewport height. When n exceeds viewport (e.g., 500 lines of output), the terminal follows the cursor above the visible area and the viewport jumps to top. This happens on every re-render — and there's no throttle, so it fires dozens of times per second during streaming output. TL;DR — Fix (verified on v2.1.81, tested on Windows): CLI_JS="$(find /tmp "$TMPDIR" "$LOCALAPPDATA/Temp" -path '/claude-code-src/package/cli.js' 2>/dev/null | head -1)" # Fix 1: HF7 — Ink renderer clear (1 occurrence) sed -i 's/function HF7(A){if(A<=0)return"";/function HF7(A){A=Math.min(A,process.stdout.rows||24);if(A<=0)return"";/' "$CLI_JS" # Fix 2+3: eraseLines — prompt renderer (2 occurrences) sed -i 's/eraseLines=(A)=>{let q=""/eraseLines=(A)=>{A=Math.min(A,process.stdout.rows||24);let q=""/g' "$CLI_JS" Restart Claude Code. Scroll stays stable during output. TL;DR — Quick test without patching your install: CLI_JS="$(find /tmp "$TMPDIR" "$LOCALAPPDATA/Temp" -path '/claude-code-src/package/cli.js' 2>/dev/null | head -1)" cp "$CLI_JS" "$(dirname "$CLI_JS")/cli-scroll-fixed.js" sed -i 's/function HF7(A){if(A<=0)return"";/function HF7(A){A=Math.min(A,process.stdout.rows||24);if(A<=0)return"";/' "$(dirname "$CLI_JS")/cli-scroll-fixed.js" sed -i 's/eraseLines=(A)=>{let q=""/eraseLines=(A)=>{A=Math.min(A,process.stdout.rows||24);let q=""/g' "$(dirname "$CLI_JS")/cli-scroll-fixed.js" node "$(dirname "$CLI_JS")/cli-scroll-fixed.js"# Generate long output, scroll up while streaming — viewport stays in place ------------------------------ What happens While Claude generates output (code, tool results, thinking), the terminal viewport jumps to the top of scrollback on every re-render. You can't read, select, or copy anything. Have to scroll down hundreds of lines to get back. This triggers dozens of times per second because the Ink renderer has no throttle — every state change (each streamed token) triggers a full re-render. Root cause (source code analysis) Decompiled cli.js v2.1.81. Three functions generate cursor-up sequences without clamping to viewport height. Variable names below are the actual minified names from cli.js: Function 1 — HF7() (Ink renderer clear, 1 occurrence): // Clears A lines: loops eraseLine + cursorUp(1) per line// When A = 500, generates 500 cursor-up sequences → viewport follows cursor to topfunction HF7(A) { if (A <= 0) return ""; // A is NOT clamped — can be hundreds let q = ""; for (let K = 0; K < A; K++) { q += x29; // \x1b[2K (erase line) if (K < A - 1) q += zF7(1); // \x1b[1A (cursor up 1) } q += b29; return q;} Functions 2+3 — eraseLines (prompt renderer, 2 occurrences): // Same pattern, two copies of the ansi module (v_ and T_)// Called with this.height which grows with outputv_.eraseLines = (A) => { let q = ""; for (let K = 0; K < A; K++) q += v_.eraseLine + (K < A - 1 ? v_.cursorUp() : ""); if (A) q += v_.cursorLeft; return q;}; Call chain: Claude streams output → Ink re-renders (no throttle, every token) → gf1() wraps in synchronized update (\x1b[?2026h...\x1b[?2026l) → "clear" → HF7(previousHeight) ← cursor-up × previousHeight → prompt → eraseLines(this.height) ← cursor-up × this.height → stdout.write(everything at once) → terminal follows cursor above viewport → JUMP Synchronized updates (CSI 2026) make it worse on Windows Terminal — microsoft/terminal#14774 <https://github.com/microsoft/terminal/issues/14774> causes SetConsoleCursorPosition to scroll viewport to cursor even inside sync blocks. The fix Add A = Math.min(A, process.stdout.rows || 24) at the start of each function. This clamps the cursor-up count to the terminal viewport height — never moves the cursor above what's visible. All three patterns are unique in cli.js v2.1.81: Function Pattern Occurrences HF7 function HF7(A){if(A<=0)return""; 1 eraseLines eraseLines=(A)=>{let q="" 2 How to apply 1. Find cli.js: # Windows (Git Bash): CLI_JS="$(find "$LOCALAPPDATA/Temp" -path '/claude-code-src/package/cli.js' 2>/dev/null | head -1)"# macOS: CLI_JS="$(find "$TMPDIR" -path '/claude-code-src/package/cli.js' 2>/dev/null | head -1)"# Linux: CLI_JS="$(find /tmp -path '/claude-code-src/package/cli.js' 2>/dev/null | head -1)"echo "$CLI_JS" # If empty, run claude once first to extract it 2. Apply (3 sed commands): sed -i 's/function HF7(A){if(A<=0)return"";/function HF7(A){A=Math.min(A,process.stdout.rows||24);if(A<=0)return"";/' "$CLI_JS" sed -i 's/eraseLines=(A)=>{let q=""/eraseLines=(A)=>{A=Math.min(A,process.stdout.rows||24);let q=""/g' "$CLI_JS" 3. Verify: # Should print 1: grep -c 'function HF7(A){A=Math.min' "$CLI_JS"# Should print 2: grep -c 'eraseLines=(A)=>{A=Math.min' "$CLI_JS" 4. Restart Claude Code — viewport stays stable during output. Note: the binary may re-extract cli.js on update, so the patch needs reapplying after Claude Code updates. Comparison with scroll-fix plugin (PR #35683 <https://github.com/anthropics/claude-code/pull/35683>) Aware of @cruzlauroiii <https://github.com/cruzlauroiii>'s scroll-fix plugin. Different approach: This fix (sed) scroll-fix plugin Approach Clamp at source (3 functions) Monkey-patch process.stdout.write, regex scan all output Complexity 3 sed one-liners ~600 char IIFE + Ctrl+6 freeze toggle Child process bug No Yes — NODE_OPTIONS inherited, hangs npm/node-gyp ( #35683 <https://github.com/anthropics/claude-code/pull/35683> comments) Coverage 3 specific cursor-up generators All stdout writes (catch-all) The plugin is a catch-all that also adds a freeze toggle. This fix is surgical — patches the 3 functions that actually generate excessive cursor-up, no side effects, no event loop leak. Platform coverage The fix clamps to process.stdout.rows which is available on all platforms. The cursor-up sequences are standard ANSI — the bug and the fix are platform-independent. Tested on Windows Terminal. Should work on macOS (iTerm2, Terminal.app) and Linux terminals since they all follow the cursor on \x1b[nA when n exceeds viewport. Related issues - #33367 <https://github.com/anthropics/claude-code/issues/33367>, #33719 <https://github.com/anthropics/claude-code/issues/33719>, #34794 <https://github.com/anthropics/claude-code/issues/34794>, #35403 <https://github.com/anthropics/claude-code/issues/35403>, #36582 <https://github.com/anthropics/claude-code/issues/36582>, #36816 <https://github.com/anthropics/claude-code/issues/36816> — Duplicates - PR #35683 <https://github.com/anthropics/claude-code/pull/35683> — scroll-fix plugin (not merged) - PR #34798 <https://github.com/anthropics/claude-code/pull/34798> — Earlier fix attempts v1-v7 - microsoft/terminal#14774 <https://github.com/microsoft/terminal/issues/14774> — Windows Terminal cursor-follow bug — Reply to this email directly, view it on GitHub <https://github.com/anthropics/claude-code/issues/33814?email_source=notifications&email_token=AII7PIAA6LKWJA4XKCY4HP34R3MRPA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMJQGM4DSNBTGM2KM4TFMFZW63VHMNXW23LFNZ2KKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4103894334>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AII7PIEA7ALEDIEQNXLK6RT4R3MRPAVCNFSM6AAAAACWQL2S5OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DCMBTHA4TIMZTGQ> . You are receiving this because you commented.Message ID: @.**>
felipekj · 3 months ago

+1 — experiencing this on GNOME Terminal (same behavior as IntelliJ terminal). Cursor randomly scrolls up during streaming output.

sasha-id · 3 months ago

+1

rut31337 · 3 months ago

+1 iTerm 3.6.9 love me some claude code but you have to fix this.

evolsb · 3 months ago

Experiencing this on Ghostty (macOS). Confirmed that Ghostty's scroll-to-bottom = no-output config has no effect — the issue is Claude Code's Ink renderer emitting cursor-repositioning escape sequences (\x1b[<N>A) on every redraw, which bypasses terminal scroll settings entirely.

For anyone on macOS/Linux looking for a workaround, claude-chill (a Rust PTY proxy) or running inside tmux are the current best options.

This is easily the most disruptive UX issue in daily use — would love to see the community PR (#35683) reviewed or an official fix prioritized.

sstraus · 3 months ago

👍 We're experiencing the same issue embedding xterm.js 6.0.0 in a Tauri app. The scroll position jumps when Claude Code redraws its TUI while the user is scrolled up. Confirmed root cause: cursor-up sequences exceeding viewport height + ESC[2J/ESC[3J.

sasha-id · 3 months ago

https://code.claude.com/docs/en/changelog

  • Fixed scrollback jumping when collapsed read/search groups finish after scrolling offscreen
  • Fixed scrollback jumping to top when the model starts or stops thinking

Is it fixed!?

arekm · 3 months ago

I just encountered scroll back to beginning of scroll history (claude 2.1.83; iterm2 3.6.9; no tmux/screen) but it is first time for half of a day playing with 2.1.83 claude cli. So seems to be "mostly fixed" (for me).

yurukusa · 3 months ago

This scrolling issue is part of a broader pattern (#826, #769, #1486, #367, #33814) where Claude Code's TUI rendering causes unintended scroll behavior.
Workaround 1 — tmux isolates scrolling:

tmux new-session -s claude 'claude'

tmux manages its own viewport independently of the terminal's scroll buffer. Scroll with Ctrl+B [ in tmux instead of using the terminal's native scroll.
Workaround 2 — Compact to reduce rendered history:

/compact

Less conversation history = less content to render = less scrolling issues. Compact at natural breakpoints.
Workaround 3 — Reduce terminal scrollback:

  • iTerm2: Preferences → Profiles → Terminal → reduce "Scrollback lines" (try 1000)
  • Windows Terminal: Profile → Advanced → History size → reduce

Smaller scrollback buffers reduce the range of scroll-jumping.
Workaround 4 — Fresh sessions for new tasks:

claude  # Start fresh instead of continuing long sessions

Workaround 5 — Use headless mode for non-interactive work:

claude -p "your task" > output.md

No TUI = no scrolling issues.

loekj · 3 months ago
This scrolling issue is part of a broader pattern (#826, #769, #1486, #367, #33814) where Claude Code's TUI rendering causes unintended scroll behavior. Workaround 1 — tmux isolates scrolling: tmux new-session -s claude 'claude' tmux manages its own viewport independently of the terminal's scroll buffer. Scroll with Ctrl+B [ in tmux instead of using the terminal's native scroll. Workaround 2 — Compact to reduce rendered history: `` /compact `` Less conversation history = less content to render = less scrolling issues. Compact at natural breakpoints. Workaround 3 — Reduce terminal scrollback: iTerm2: Preferences → Profiles → Terminal → reduce "Scrollback lines" (try 1000) Windows Terminal: Profile → Advanced → History size → reduce Smaller scrollback buffers reduce the range of scroll-jumping. Workaround 4 — Fresh sessions for new tasks: claude # Start fresh instead of continuing long sessions Workaround 5 — Use headless mode for non-interactive work: claude -p "your task" > output.md No TUI = no scrolling issues.

At some point they had it fixed. Unsure what exact version that was since they release new version at a faster clip than uncle Earl commits felonies.

Any patch so far proposed is just not really a good work around.

claude[bot] contributor · 2 months ago

This is a duplicate of #35403, which was fixed as of version 2.1.101.

github-actions[bot] · 2 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.