Skip to content

fix(pages): DocsPage does not scroll to in-page anchor on initial load / deep link #412

Description

@lizhengfeng101

Description

DocsPage handles in-page anchor scrolling only on click (via handleContentClick and scrollToHeading). It never reads location.hash when the page first mounts, so deep-linking to a heading does not scroll to it.

Open a URL such as .../#/docs/faq#超时 (or .../#/docs/configuration#timeouts) directly in a fresh tab: the correct doc renders, but the viewport stays at the top instead of scrolling to the 超时 / Timeouts heading. Clicking the same link from within the app works, because that path goes through the click handler.

Note the site uses HashRouter (pages/src/index.tsx), so the routed URL is #/docs/faq#超时 — react-router parses this into pathname: "/docs/faq" and hash: "#超时". A fix should read the fragment from useLocation().hash, not from window.location.hash directly.

Current behavior:

  • Click an in-page link inside the app → scrolls ✅ (handleContentClick, DocsPage.tsx:199-233)
  • Load/refresh a URL that already contains a heading fragment → no scroll ❌ (nothing reads the hash on mount)

Expected behavior:

  • On initial mount (and whenever location.hash changes), scroll the matching heading into view, mirroring the existing click behavior.

Scope

  • File: pages/src/pages/DocsPage.tsx
  • Area: add an effect that runs after the doc content renders, reads useLocation().hash, decodes it, and scrolls the target heading into view.
  • Reuse the existing decodeFragment helper (already in DocsPage.tsx) — marked percent-encodes non-ASCII fragments while heading ids are raw text from generateHeadingId, so the fragment must be decoded before getElementById.
  • Headings are rendered asynchronously from markdown, so the lookup likely needs the same requestAnimationFrame retry pattern already used in the cross-page anchor path (DocsPage.tsx:222-230).

Acceptance Criteria

  • Loading .../#/docs/faq#超时 (zh), .../#/docs/faq#no-tool-calls-parsed-local-models-ollama (en), and .../#/docs/configuration#timeouts directly scrolls to the target heading.
  • Works for CJK fragments (decoded via decodeFragment).
  • Existing in-app click-to-scroll behavior is unchanged.
  • No scroll/console error when the fragment is empty or does not match any heading.
  • Code check passes (make check)

Context

Discovered during review of #400, which added CJK cross-links to the docs and fixed click-time anchor decoding (decodeFragment). The mount-time / deep-link case was explicitly noted as out of scope there and is filed here as a follow-up. The decodeFragment helper introduced by #400 should be reused for consistency.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions