Skip to content

Commit 15b5f97

Browse files
fix: prevent scroll jump when editing large messages (open-webui#21402)
Save and restore scroll positions around textarea auto-resize to avoid layout shifts. Use preventScroll on focus.
1 parent ca0983f commit 15b5f97

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

src/lib/components/chat/Messages/ResponseMessage.svelte

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,13 @@
365365
366366
await tick();
367367
368+
const messagesContainer = document.getElementById('messages-container');
369+
const savedScrollTop = messagesContainer?.scrollTop;
370+
368371
editTextAreaElement.style.height = '';
369372
editTextAreaElement.style.height = `${editTextAreaElement.scrollHeight}px`;
373+
374+
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
370375
};
371376
372377
const editMessageConfirmHandler = async () => {
@@ -697,8 +702,13 @@
697702
class=" bg-transparent outline-hidden w-full resize-none"
698703
bind:value={editedContent}
699704
on:input={(e) => {
705+
const messagesContainer = document.getElementById('messages-container');
706+
const savedScrollTop = messagesContainer?.scrollTop;
707+
700708
e.target.style.height = '';
701709
e.target.style.height = `${e.target.scrollHeight}px`;
710+
711+
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
702712
}}
703713
on:keydown={(e) => {
704714
if (e.key === 'Escape') {

src/lib/components/chat/Messages/UserMessage.svelte

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
let editedFiles = [];
5151
5252
let messageEditTextAreaElement: HTMLTextAreaElement;
53+
let editScrollContainer: HTMLDivElement;
5354
5455
let message = JSON.parse(JSON.stringify(history.messages[messageId]));
5556
$: if (history.messages) {
@@ -73,10 +74,14 @@
7374
await tick();
7475
7576
if (messageEditTextAreaElement) {
77+
const messagesContainer = document.getElementById('messages-container');
78+
const savedScrollTop = messagesContainer?.scrollTop;
79+
7680
messageEditTextAreaElement.style.height = '';
7781
messageEditTextAreaElement.style.height = `${messageEditTextAreaElement.scrollHeight}px`;
7882
79-
messageEditTextAreaElement?.focus();
83+
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
84+
messageEditTextAreaElement?.focus({ preventScroll: true });
8085
}
8186
};
8287
@@ -283,15 +288,22 @@
283288
</div>
284289
{/if}
285290

286-
<div class="max-h-96 overflow-auto">
291+
<div class="max-h-96 overflow-auto" bind:this={editScrollContainer}>
287292
<textarea
288293
id="message-edit-{message.id}"
289294
bind:this={messageEditTextAreaElement}
290295
class=" bg-transparent outline-hidden w-full resize-none"
291296
bind:value={editedContent}
292297
on:input={(e) => {
298+
const messagesContainer = document.getElementById('messages-container');
299+
const savedScrollTop = messagesContainer?.scrollTop;
300+
const savedInnerScroll = editScrollContainer?.scrollTop;
301+
293302
e.target.style.height = '';
294303
e.target.style.height = `${e.target.scrollHeight}px`;
304+
305+
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
306+
if (editScrollContainer) editScrollContainer.scrollTop = savedInnerScroll;
295307
}}
296308
on:keydown={(e) => {
297309
if (e.key === 'Escape') {

0 commit comments

Comments
 (0)