Skip to content

Commit 179c679

Browse files
committed
fix: prevent unwanted auto-scrolling in reasoning block during thinking
- Add scroll position tracking to ReasoningBlock component - Only auto-scroll when user is already near bottom (within 10px tolerance) - Preserve user scroll position when reading thoughts from beginning - Fixes issue #5874 where users could not read thoughts properly due to forced scrolling The implementation follows the same pattern used in CodeBlock.tsx for consistent UX.
1 parent 38d8edf commit 179c679

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

webview-ui/src/components/chat/ReasoningBlock.tsx

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ interface ReasoningBlockProps {
1212
onToggleCollapse?: () => void
1313
}
1414

15+
// Tolerance for determining if user is "near bottom" (in pixels)
16+
const SCROLL_SNAP_TOLERANCE = 10
17+
1518
export const ReasoningBlock = ({ content, elapsed, isCollapsed = false, onToggleCollapse }: ReasoningBlockProps) => {
1619
const contentRef = useRef<HTMLDivElement>(null)
1720
const elapsedRef = useRef<number>(0)
@@ -21,10 +24,41 @@ export const ReasoningBlock = ({ content, elapsed, isCollapsed = false, onToggle
2124
const [isTransitioning, setIsTransitioning] = useState<boolean>(false)
2225
const cursorRef = useRef<number>(0)
2326
const queueRef = useRef<string[]>([])
27+
28+
// Track if user was scrolled near bottom before content update
29+
const wasNearBottomRef = useRef(true) // Start as true for initial auto-scroll
30+
31+
// Check if user is near the bottom of the scroll container
32+
const isNearBottom = useCallback(() => {
33+
if (!contentRef.current) return false
34+
const { scrollTop, scrollHeight, clientHeight } = contentRef.current
35+
return Math.abs(scrollHeight - scrollTop - clientHeight) <= SCROLL_SNAP_TOLERANCE
36+
}, [])
37+
38+
// Effect to listen to scroll events and update the ref
39+
useEffect(() => {
40+
const element = contentRef.current
41+
if (!element || isCollapsed) return
42+
43+
const handleScroll = () => {
44+
wasNearBottomRef.current = isNearBottom()
45+
}
46+
47+
element.addEventListener("scroll", handleScroll, { passive: true })
48+
// Initial check in case it starts scrolled up
49+
handleScroll()
50+
51+
return () => {
52+
element.removeEventListener("scroll", handleScroll)
53+
}
54+
}, [isNearBottom, isCollapsed])
2455

56+
// Only auto-scroll if user was near bottom before content update
2557
useEffect(() => {
26-
if (contentRef.current && !isCollapsed) {
58+
if (contentRef.current && !isCollapsed && wasNearBottomRef.current) {
2759
contentRef.current.scrollTop = contentRef.current.scrollHeight
60+
// Update the ref since we just scrolled to bottom
61+
wasNearBottomRef.current = true
2862
}
2963
}, [content, isCollapsed])
3064

0 commit comments

Comments
 (0)