diff --git a/.changeset/scroll-to-anchor-soft-nav.md b/.changeset/scroll-to-anchor-soft-nav.md new file mode 100644 index 000000000..0418cfa07 --- /dev/null +++ b/.changeset/scroll-to-anchor-soft-nav.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fix anchor links (e.g. `/page#heading`) not scrolling to the target heading during client-side navigation between pages. diff --git a/packages/gitbook/src/components/hooks/useScrollPage.ts b/packages/gitbook/src/components/hooks/useScrollPage.ts index a2751b317..565de8916 100644 --- a/packages/gitbook/src/components/hooks/useScrollPage.ts +++ b/packages/gitbook/src/components/hooks/useScrollPage.ts @@ -69,12 +69,20 @@ export function ScrollPage() { */ export function useScrollToHash() { const hash = useHash(); + const pathname = usePathname(); + // Depend on `pathname` as well as `hash`: on a soft navigation to another page + // (e.g. a homepage card linking to `/page#heading`), the hash is set on click while + // the previous page is still mounted, so a hash-only effect fires before the target + // element exists. Because sibling pages share the same `[pagePath]` route, this hook's + // host component is reused rather than remounted, so it would otherwise never re-run + // once the destination content commits. Re-running on `pathname` re-attempts the scroll + // when the target heading is finally in the DOM. React.useEffect(() => { if (hash) { scrollToHash(hash); } - }, [hash]); + }, [hash, pathname]); } /**