Skip to content

Commit 85ecbb2

Browse files
committed
Make anchor underlines react better to clicks
This ensures that the anchor that is clicked is always the one that gets underlined, even if just scrolling to that heading would underline a different anchor. Using `onhashchange` alone instead of adding `onclick`s to each anchor is not sufficient because it's possible to click on an anchor that already has its hash in the URL but has been scrolled away from.
1 parent 722be43 commit 85ecbb2

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

apps/svelte.dev/src/routes/docs/[topic]/[...path]/OnThisPage.svelte

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,28 @@
66
77
let headings: NodeListOf<HTMLHeadingElement>;
88
let current = $state('');
9+
let locked = $state(false);
910
1011
afterNavigate(() => {
11-
current = location.hash.slice(1);
1212
headings = content.querySelectorAll('h2');
13-
update(); // Ensure active link is set correctly on navigation
13+
for (const heading of headings) {
14+
const anchor = heading.querySelector('a');
15+
if (anchor) anchor.onclick = onclick;
16+
}
17+
onclick();
1418
});
1519
16-
// Update function to activate the correct section link
17-
function update() {
20+
function onclick() {
21+
current = location.hash.slice(1);
22+
// avoid onscroll handler from inaccurately updating
23+
locked = true;
24+
setTimeout(() => (locked = false), 100);
25+
}
26+
27+
function onscroll() {
28+
if (locked) return;
29+
1830
const threshold = (innerHeight * 1) / 3;
19-
let found = false;
2031
2132
for (let i = 0; i < headings.length; i++) {
2233
const heading = headings[i];
@@ -28,19 +39,18 @@
2839
(!next || next.getBoundingClientRect().top > threshold)
2940
) {
3041
current = heading.id;
31-
found = true;
3242
break;
3343
}
3444
}
3545
3646
// Handle case when scrolled to the top of the page
37-
if (!found && scrollY === 0) {
47+
if (scrollY === 0) {
3848
current = '';
3949
}
4050
}
4151
</script>
4252

43-
<svelte:window onscroll={update} onhashchange={() => (current = location.hash.slice(1))} />
53+
<svelte:window {onscroll} onhashchange={onclick} />
4454

4555
<aside class="on-this-page">
4656
<label>
@@ -51,14 +61,15 @@
5161
<nav>
5262
<ul>
5363
<li>
54-
<a href="/{document.slug}" class:active={current === ''}>
64+
<a href="/{document.slug}" class:active={current === ''} {onclick}>
5565
{document.metadata.title}
5666
</a>
5767
</li>
5868

5969
{#each document.sections as section}
6070
<li>
61-
<a href="#{section.slug}" class:active={current === section.slug}>{@html section.title}</a
71+
<a href="#{section.slug}" class:active={current === section.slug} {onclick}
72+
>{@html section.title}</a
6273
>
6374
</li>
6475
{/each}

0 commit comments

Comments
 (0)