From 9d62cb4bad8d41207d41b5f87d4cfee177a6864d Mon Sep 17 00:00:00 2001 From: Peter White <1788320+peterwhite@users.noreply.github.com> Date: Tue, 13 Oct 2026 09:25:16 +0200 Subject: [PATCH] Keep TOC scroll position when expanding a group (#4678) --- .changeset/calm-toc-expand.md | 5 +++++ .../src/components/primitives/ScrollContainer.tsx | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .changeset/calm-toc-expand.md diff --git a/.changeset/calm-toc-expand.md b/.changeset/calm-toc-expand.md new file mode 100644 index 000000000..5ea1aa053 --- /dev/null +++ b/.changeset/calm-toc-expand.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fix table of contents scrolling back to the current page when expanding another group. diff --git a/packages/gitbook/src/components/primitives/ScrollContainer.tsx b/packages/gitbook/src/components/primitives/ScrollContainer.tsx index d5b1aa459..408ba78be 100644 --- a/packages/gitbook/src/components/primitives/ScrollContainer.tsx +++ b/packages/gitbook/src/components/primitives/ScrollContainer.tsx @@ -100,11 +100,19 @@ export function ScrollContainer(props: ScrollContainerProps) { } let frame = 0; + let previousActiveItems = new Set(container.querySelectorAll(active)); // Active items can mount only after a collapsed group expands. const observer = new MutationObserver(() => { cancelAnimationFrame(frame); frame = requestAnimationFrame(() => { - for (const activeItem of container.querySelectorAll(active)) { + const activeItems = new Set(container.querySelectorAll(active)); + const newActiveItems = [...activeItems].filter( + (item) => !previousActiveItems.has(item) + ); + previousActiveItems = activeItems; + // Only follow newly active items so unrelated changes (e.g. expanding another + // group) don't pull the user back to the current page. + for (const activeItem of newActiveItems) { if (!isElementFullyVisibleInContainer(activeItem, container)) { scrollToElementInContainer(activeItem, container, 'smooth'); return;