diff --git a/apps/web/src/components/chat/MessagesTimeline.test.tsx b/apps/web/src/components/chat/MessagesTimeline.test.tsx
index 076873bca4f..cd03feb8262 100644
--- a/apps/web/src/components/chat/MessagesTimeline.test.tsx
+++ b/apps/web/src/components/chat/MessagesTimeline.test.tsx
@@ -9,6 +9,7 @@ vi.mock("@legendapp/list/react", async () => {
const LegendList = (props: {
data: Array<{ id: string }>;
+ extraData?: unknown;
keyExtractor: (item: { id: string }) => string;
renderItem: (args: { item: { id: string } }) => ReactNode;
ListHeaderComponent?: ReactNode;
@@ -48,6 +49,7 @@ vi.mock("@legendapp/list/react", async () => {
return (
{
expect(markup).toContain('data-anchor-on-ready="true"');
expect(markup).not.toContain("data-anchor-max-size=");
expect(markup).toContain('data-content-inset-end="144"');
+ expect(markup).toContain('data-extra-data-matches-rows="true"');
expect(markup).toContain("[overflow-anchor:none]");
expect(markup).not.toContain('data-maintain-scroll-at-end="enabled"');
expect(markup).toContain('data-maintain-visible-content-position="object"');
diff --git a/apps/web/src/components/chat/MessagesTimeline.tsx b/apps/web/src/components/chat/MessagesTimeline.tsx
index 52ccf07ed13..861218a41ac 100644
--- a/apps/web/src/components/chat/MessagesTimeline.tsx
+++ b/apps/web/src/components/chat/MessagesTimeline.tsx
@@ -532,7 +532,11 @@ export const MessagesTimeline = memo(function MessagesTimeline({
// from TimelineRowCtx, which propagates through LegendList's memo.
const renderItem = useCallback(
({ item }: { item: MessagesTimelineRow }) => (
-
+
),
@@ -567,6 +571,12 @@ export const MessagesTimeline = memo(function MessagesTimeline({
ref={listRef}
data={rows}
+ // LegendList can retain a mounted container's previous child while
+ // anchored end-space is recomputed around a newly inserted turn.
+ // Re-running mounted renderers on each logical row-set change keeps
+ // the container content aligned with its current item key; memoized
+ // TimelineRowContent still skips unchanged rows.
+ extraData={rows}
keyExtractor={keyExtractor}
getItemType={getItemType}
renderItem={renderItem}