From f37b2504797f3ea2fa239ecb364dce379a2d7d76 Mon Sep 17 00:00:00 2001 From: Deon Sanchez <69873175+deon-sanchez@users.noreply.github.com> Date: Wed, 4 Mar 2026 10:44:22 -0700 Subject: [PATCH] fix: playground does not scroll down to the latest user message upon sending (Regression) (#12006) * fixes scroll is on input message * feat: re-engage Safari sticky scroll mode when user sends message Add custom event 'langflow-scroll-to-bottom' to force SafariScrollFix back into sticky mode when user sends a new message. This ensures the chat scrolls to bottom even if user had scrolled up, fixing behavior where Safari's scroll fix would remain disengaged after manual scrolling. --- .../components/common/safari-scroll-fix.tsx | 7 ++++++ .../flow-page-sliding-container.tsx | 24 +++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/components/common/safari-scroll-fix.tsx b/src/frontend/src/components/common/safari-scroll-fix.tsx index 9982c38fdc..9cf21a91f3 100644 --- a/src/frontend/src/components/common/safari-scroll-fix.tsx +++ b/src/frontend/src/components/common/safari-scroll-fix.tsx @@ -86,10 +86,16 @@ function SafariScrollFixInner() { } }; + const onForceSticky = () => { + stickyRef.current = true; + lastKnownScrollTop.current = scrollEl.scrollTop; + }; + scrollEl.addEventListener("wheel", onWheel, { passive: true }); scrollEl.addEventListener("touchstart", onTouchStart, { passive: true }); scrollEl.addEventListener("touchmove", onTouchMove, { passive: true }); scrollEl.addEventListener("scroll", onScroll, { passive: true }); + window.addEventListener("langflow-scroll-to-bottom", onForceSticky); let rafId: ReturnType; const tick = () => { @@ -120,6 +126,7 @@ function SafariScrollFixInner() { scrollEl.removeEventListener("touchstart", onTouchStart); scrollEl.removeEventListener("touchmove", onTouchMove); scrollEl.removeEventListener("scroll", onScroll); + window.removeEventListener("langflow-scroll-to-bottom", onForceSticky); cancelAnimationFrame(rafId); }; }, [scrollRef, stopScroll]); diff --git a/src/frontend/src/components/core/playgroundComponent/sliding-container/components/flow-page-sliding-container.tsx b/src/frontend/src/components/core/playgroundComponent/sliding-container/components/flow-page-sliding-container.tsx index 6f33529733..237e034521 100644 --- a/src/frontend/src/components/core/playgroundComponent/sliding-container/components/flow-page-sliding-container.tsx +++ b/src/frontend/src/components/core/playgroundComponent/sliding-container/components/flow-page-sliding-container.tsx @@ -1,5 +1,5 @@ -import { useEffect, useMemo, useState } from "react"; -import { StickToBottom } from "use-stick-to-bottom"; +import { useEffect, useMemo, useRef, useState } from "react"; +import { StickToBottom, useStickToBottom } from "use-stick-to-bottom"; import { SafariScrollFix } from "@/components/common/safari-scroll-fix"; import { ChatHeader } from "@/components/core/playgroundComponent/chat-view/chat-header/components/chat-header"; import { ChatSidebar } from "@/components/core/playgroundComponent/chat-view/chat-header/components/chat-sidebar"; @@ -97,6 +97,23 @@ export function FlowPageSlidingContainerContent({ } }, [chatHistory.length, isBuilding, inputs, nodes, setChatValueStore]); + const stickyInstance = useStickToBottom({ + resize: "instant", + initial: "instant", + }); + + const prevChatLenRef = useRef(chatHistory.length); + useEffect(() => { + if (chatHistory.length > prevChatLenRef.current) { + const lastMsg = chatHistory[chatHistory.length - 1]; + if (lastMsg?.isSend) { + window.dispatchEvent(new Event("langflow-scroll-to-bottom")); + stickyInstance.scrollToBottom("smooth"); + } + } + prevChatLenRef.current = chatHistory.length; + }, [chatHistory, stickyInstance]); + const { dragOver, dragEnter, dragLeave } = useDragAndDrop( setIsDragging, true, @@ -198,9 +215,8 @@ export function FlowPageSlidingContainerContent({ />