Summary
The Scrollspy plugin uses history.replaceState() in its scrollTo() method (source: core.ts line 164). This means clicking TOC links does not create browser history entries. When the user presses the Back button, they expect to return to the previous anchor — instead, the browser navigates away from the page entirely.
Steps to Reproduce
- Open https://preline.co/docs/scrollspy.html
- Click any anchor link in the right-side (large screen) navigation (e.g. https://preline.co/docs/scrollspy.html#example-with-nested-nav)
- Press the browser Back button
Demo Link
https://preline.co/docs/scrollspy.html
Expected Behavior
Expected: Browser scrolls back to https://preline.co/docs/scrollspy.html.
Actual Behavior
Actual: Browser navigates away from the page (back to wherever you came from).
Root cause
In scrollTo(), the plugin calls:
window.history.replaceState(null, null, link.getAttribute('href'));
replaceState updates the URL but does not create a history entry. Changing this to pushState would restore standard anchor navigation behavior. Each clicked anchor gets a history entry, and Back/Forward step through them.
Suggested fix
In src/plugins/scrollspy/core.ts, line 164, change:
window.history.replaceState(null, null, link.getAttribute('href'));
to:
window.history.pushState(null, null, link.getAttribute('href'));
A popstate listener would also be needed to scroll to the target on Back/Forward:
window.addEventListener("popstate", () => {
const id = location.hash.slice(1);
const el = id ? document.getElementById(id) : null;
if (el) el.scrollIntoView({ behavior: "smooth" });
});
Workaround
Add a capture-phase click listener that calls pushState before the Scrollspy handler runs. Scrollspy's subsequent replaceState harmlessly overwrites the same hash:
document.addEventListener("click", (e) => {
const link = e.target.closest('a[href^="#"]');
if (link) history.pushState(null, "", link.getAttribute("href"));
}, true);
window.addEventListener("popstate", () => {
const id = location.hash.slice(1);
const el = id ? document.getElementById(id) : null;
if (el) el.scrollIntoView({ behavior: "smooth" });
});
Environment
- Preline UI v4.1.3
- Tested in Chrome 134, Safari 18.4, macOS
Screenshots
No response
Summary
The Scrollspy plugin uses
history.replaceState()in itsscrollTo()method (source: core.ts line 164). This means clicking TOC links does not create browser history entries. When the user presses the Back button, they expect to return to the previous anchor — instead, the browser navigates away from the page entirely.Steps to Reproduce
Demo Link
https://preline.co/docs/scrollspy.html
Expected Behavior
Expected: Browser scrolls back to https://preline.co/docs/scrollspy.html.
Actual Behavior
Actual: Browser navigates away from the page (back to wherever you came from).
Root cause
In
scrollTo(), the plugin calls:replaceStateupdates the URL but does not create a history entry. Changing this topushStatewould restore standard anchor navigation behavior. Each clicked anchor gets a history entry, and Back/Forward step through them.Suggested fix
In
src/plugins/scrollspy/core.ts, line 164, change:to:
A
popstatelistener would also be needed to scroll to the target on Back/Forward:Workaround
Add a capture-phase click listener that calls
pushStatebefore the Scrollspy handler runs. Scrollspy's subsequentreplaceStateharmlessly overwrites the same hash:Environment
Screenshots
No response