@@ -60,6 +60,8 @@ export const useScrollLocationLogic = (params: UseScrollLocationLogicParams) =>
6060 const closeToTop = useRef ( false ) ;
6161 const previousScrollTopRef = useRef ( 0 ) ;
6262 const previousMessagesLengthRef = useRef ( messages . length ) ;
63+ const previousDisableAutoScrollToBottomRef = useRef ( disableAutoScrollToBottom ) ;
64+ const previousDisableAutoScrollSettleRef = useRef ( disableAutoScrollToBottom ) ;
6365 const anchorRestoreCleanupRef = useRef < ( ( ) => void ) | null > ( null ) ;
6466
6567 const captureAnchor = useCallback ( ( ) => {
@@ -249,6 +251,16 @@ export const useScrollLocationLogic = (params: UseScrollLocationLogicParams) =>
249251 * path where existing viewport position must be preserved.
250252 */
251253 useLayoutEffect ( ( ) => {
254+ const disableAutoScrollJustReleased =
255+ previousDisableAutoScrollToBottomRef . current && ! disableAutoScrollToBottom ;
256+ previousDisableAutoScrollToBottomRef . current = disableAutoScrollToBottom ;
257+
258+ // Re-enabling auto-scroll should not immediately force a jump to bottom.
259+ // This avoids snap-back after temporary suppression (e.g. jump-to-message).
260+ if ( disableAutoScrollJustReleased ) {
261+ return ;
262+ }
263+
252264 if ( listElement ) {
253265 setWrapperRect ( listElement . getBoundingClientRect ( ) ) ;
254266 }
@@ -275,6 +287,19 @@ export const useScrollLocationLogic = (params: UseScrollLocationLogicParams) =>
275287 * to catch late layout updates without keeping the list in a prolonged lock loop.
276288 */
277289 useLayoutEffect ( ( ) => {
290+ const disableAutoScrollJustReleased =
291+ previousDisableAutoScrollSettleRef . current && ! disableAutoScrollToBottom ;
292+ previousDisableAutoScrollSettleRef . current = disableAutoScrollToBottom ;
293+
294+ // Skip one settle cycle when auto-scroll suppression is released.
295+ // Without this guard, a jump-to-message flow can scroll to the target and then
296+ // get pulled back down by the delayed "keep pinned to bottom" retries
297+ // (80/260/420/900/1700ms), which looks like a snap-back to the latest message.
298+ // Letting this transition frame pass preserves the jump destination.
299+ if ( disableAutoScrollJustReleased ) {
300+ return ;
301+ }
302+
278303 if (
279304 ! listElement ||
280305 disableAutoScrollToBottom ||
0 commit comments