Skip to content

Commit e2ef311

Browse files
ehfengclaude
andcommitted
Trigger sidebar scroll on data-current-path mutation
Mintlify has no navigation event, but it rewrites the data-current-path attribute on <html> on every client-side route change. Observing that attribute replaces the history.pushState/replaceState monkeypatch and the setInterval poll, and removes the stale active-link race since the attribute flips in the same commit as the sidebar's aria-current. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5d56cf8 commit e2ef311

1 file changed

Lines changed: 19 additions & 44 deletions

File tree

sidebar-scroll.js

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,14 @@
1414
return null;
1515
}
1616

17-
function findActiveLink(sb) {
18-
return sb.querySelector(
19-
"a[aria-current='page'], a[aria-current='true'], a[data-active='true']"
20-
);
21-
}
22-
2317
function showActive() {
2418
var sb = findSidebar();
25-
if (!sb) return false;
26-
var link = findActiveLink(sb);
27-
if (!link) return false;
19+
if (!sb) return;
20+
var link = sb.querySelector(
21+
"a[aria-current='page'], a[aria-current='true'], a[data-active='true']"
22+
);
23+
// Guard against acting on the previous page's link before the DOM updates.
24+
if (!link || link.pathname !== location.pathname) return;
2825

2926
var sbRect = sb.getBoundingClientRect();
3027
var linkRect = link.getBoundingClientRect();
@@ -35,41 +32,19 @@
3532
} else if (linkRect.bottom > sbRect.bottom - margin) {
3633
sb.scrollTop += linkRect.bottom - (sbRect.bottom - margin);
3734
}
38-
return true;
3935
}
4036

41-
// Sidebar may not be mounted yet after a route change; retry until it is,
42-
// then re-apply once to survive a late re-render that resets scroll.
43-
function pollShow() {
44-
var attempts = 0;
45-
var iv = setInterval(function () {
46-
attempts++;
47-
if (showActive()) {
48-
clearInterval(iv);
49-
setTimeout(showActive, 150);
50-
} else if (attempts > 30) {
51-
clearInterval(iv);
52-
}
53-
}, 50);
54-
}
55-
56-
var origPush = history.pushState;
57-
history.pushState = function () {
58-
var r = origPush.apply(this, arguments);
59-
pollShow();
60-
return r;
61-
};
62-
var origReplace = history.replaceState;
63-
history.replaceState = function () {
64-
var r = origReplace.apply(this, arguments);
65-
pollShow();
66-
return r;
67-
};
68-
window.addEventListener("popstate", pollShow);
69-
70-
if (document.readyState === "complete") {
71-
pollShow();
72-
} else {
73-
window.addEventListener("load", pollShow);
74-
}
37+
// Mintlify has no navigation event, but it rewrites data-current-path on
38+
// <html> on every client-side route change. That mutation is our signal.
39+
var html = document.documentElement;
40+
var last = html.getAttribute("data-current-path");
41+
new MutationObserver(function () {
42+
var cur = html.getAttribute("data-current-path");
43+
if (cur === last) return;
44+
last = cur;
45+
requestAnimationFrame(showActive);
46+
}).observe(html, { attributes: true, attributeFilter: ["data-current-path"] });
47+
48+
if (document.readyState === "complete") showActive();
49+
else window.addEventListener("load", showActive);
7550
})();

0 commit comments

Comments
 (0)