Skip to content

Fix search highlight scroll overriding hash-fragment navigation#14141

Merged
cderv merged 1 commit intomainfrom
fix/search-hash-scroll
Mar 2, 2026
Merged

Fix search highlight scroll overriding hash-fragment navigation#14141
cderv merged 1 commit intomainfrom
fix/search-hash-scroll

Conversation

@cderv
Copy link
Collaborator

@cderv cderv commented Mar 2, 2026

When clicking a search result that links to a specific section (e.g., page.html?q=term#section), the page briefly shows the correct section but then scrolls to the first <mark> near the top of the page. Additionally, TOC and sidebar links on a highlighted page include the ?q= parameter in their href, causing full-page reloads instead of in-page navigation.

Root Cause

Two interacting issues in quarto-search.js:

  1. replaceState (removing ?q= from the URL) ran inside DOMContentLoaded, but quarto-nav.js also runs during DOMContentLoaded and resolves all <a> href attributes against window.location — which still contained ?q=. This baked the search param into every link on the page.

  2. scrollToFirstVisibleMatch() fired unconditionally via requestAnimationFrame on pageshow, overriding the browser's native hash-fragment scroll.

Fix

  • Move replaceState to module load time (before any DOMContentLoaded handlers run), so quarto-nav.js resolves link hrefs against a clean URL
  • Guard scrollToFirstVisibleMatch with a hash check — when a #fragment is present, the browser already scrolled to the target section

The original URL (including hash and query params) is captured in currentUrl before replaceState, so all downstream reads (kQuery, showSearchResults, currentUrl.hash) still work correctly.

Test Plan

  • ?q=term#section scrolls to hash target, not first match (Playwright)
  • TOC links don't retain ?q= parameter (Playwright)
  • Existing search highlight, tab activation, and scroll-to-match tests pass (33/33 across Chromium, Firefox, WebKit)
  • Both Fuse.js (built-in) and Algolia search engines use the same ?q= handler

Builds on #14053 and #14080.

When clicking a search result linking to a specific section
(e.g., page.html?q=term#section), scrollToFirstVisibleMatch()
overrode the browser's hash scroll, jumping to the first <mark>
near the top. Additionally, quarto-nav.js baked ?q= into all
link hrefs during DOMContentLoaded, causing TOC clicks to
trigger full-page reloads.

Two fixes:
- Move replaceState (removing ?q=) to module load time, before
  any DOMContentLoaded handlers run, so quarto-nav.js resolves
  link hrefs against a clean URL
- Guard scrollToFirstVisibleMatch with a hash check so browser
  hash navigation is preserved for section-level search results
@posit-snyk-bot
Copy link
Collaborator

posit-snyk-bot commented Mar 2, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@cderv cderv merged commit b3d901f into main Mar 2, 2026
82 of 93 checks passed
@cderv cderv deleted the fix/search-hash-scroll branch March 2, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants