Skip to content

fix: improve underlining in "On this page" #1312

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
zqianem committed Apr 18, 2025
commit 85ecbb267102ab183c377e3cce490c598e462fbf
31 changes: 21 additions & 10 deletions apps/svelte.dev/src/routes/docs/[topic]/[...path]/OnThisPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,28 @@

let headings: NodeListOf<HTMLHeadingElement>;
let current = $state('');
let locked = $state(false);

afterNavigate(() => {
current = location.hash.slice(1);
headings = content.querySelectorAll('h2');
update(); // Ensure active link is set correctly on navigation
for (const heading of headings) {
const anchor = heading.querySelector('a');
if (anchor) anchor.onclick = onclick;
}
onclick();
});

// Update function to activate the correct section link
function update() {
function onclick() {
current = location.hash.slice(1);
// avoid onscroll handler from inaccurately updating
locked = true;
setTimeout(() => (locked = false), 100);
}

function onscroll() {
if (locked) return;

const threshold = (innerHeight * 1) / 3;
let found = false;

for (let i = 0; i < headings.length; i++) {
const heading = headings[i];
Expand All @@ -28,19 +39,18 @@
(!next || next.getBoundingClientRect().top > threshold)
) {
current = heading.id;
found = true;
break;
}
}

// Handle case when scrolled to the top of the page
if (!found && scrollY === 0) {
if (scrollY === 0) {
current = '';
}
}
</script>

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

<aside class="on-this-page">
<label>
Expand All @@ -51,14 +61,15 @@
<nav>
<ul>
<li>
<a href="/{document.slug}" class:active={current === ''}>
<a href="/{document.slug}" class:active={current === ''} {onclick}>
{document.metadata.title}
</a>
</li>

{#each document.sections as section}
<li>
<a href="#{section.slug}" class:active={current === section.slug}>{@html section.title}</a
<a href="#{section.slug}" class:active={current === section.slug} {onclick}
>{@html section.title}</a
>
</li>
{/each}
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy