From 42e765b877df626a74cfd4f1361bf4d42042445f Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Tue, 17 Mar 2026 00:53:41 +0100 Subject: [PATCH] fix: use capture-phase load listener to scroll chat after GIF/image load ResizeObserver alone misses scroll adjustments when multiple images load in quick succession due to browser layout-loop suppression. A capture-phase load event listener on the content wrapper reliably catches all descendant image loads and re-scrolls to bottom. --- .../web/src/components/chat/MessageList.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/web/src/components/chat/MessageList.tsx b/packages/web/src/components/chat/MessageList.tsx index 39e0fe65..484ff444 100644 --- a/packages/web/src/components/chat/MessageList.tsx +++ b/packages/web/src/components/chat/MessageList.tsx @@ -125,6 +125,23 @@ export function MessageList({ channelId, jumpToMessageId, onJumpComplete }: Mess return () => observer.disconnect(); }, [hasMessages, channelId]); + // Scroll to bottom when any image/media inside the message list finishes loading. + // The `load` event doesn't bubble, but capture-phase listeners on ancestors still fire. + // This handles the case ResizeObserver misses due to its own layout-loop suppression. + useEffect(() => { + const content = contentRef.current; + if (!content) return; + + const handleMediaLoad = () => { + if (isNearBottomRef.current && containerRef.current) { + containerRef.current.scrollTop = containerRef.current.scrollHeight; + } + }; + + content.addEventListener('load', handleMediaLoad, true); + return () => content.removeEventListener('load', handleMediaLoad, true); + }, [hasMessages, channelId]); + // Jump-to-message: scroll to target and highlight useEffect(() => { if (!jumpToMessageId) return;