Component
Scrollspy
Published on
Description
A scrollspy highlights the navigation link for the section currently in view, giving the reader a persistent sense of place within a long document. It wraps a table of contents whose links are in-page anchors; as the reader scrolls, the link for the section in the top half of the viewport is marked as current.
The pattern is progressive: with no scripting the navigation is still a plain list of working jump links. The ds-scrollspy web component lazy-loads and layers the active highlighting on top using an IntersectionObserver.
This is a transitional implementation. The vanilla styles already set scroll-target-group: auto on the navigation and highlight the active link with the native :target-current selector. The JavaScript component only defines itself when CSS.supports("scroll-target-group", "auto") is false, so it removes itself automatically once native CSS scroll-target-group reaches baseline support.
Example
Usage
Wrap the table of contents in <nav is="ds-scrollspy">. Each <a href="#id"> points at the id of a section heading, and every target section needs a matching <h2 id> so the observer can track it. The observer looks up section:has(h2[id]) first, then falls back to any element carrying that id. A page opened at a #hash, and later hashchange events, set the active link too.
<nav is="ds-scrollspy" aria-labelledby="toc-label">
<section>
<header><h2 id="toc-label">On this page</h2></header>
<ol>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#usage">Usage</a></li>
<li><a href="#accessibility">Accessibility</a></li>
</ol>
</section>
</nav>
<section>
<h2 id="introduction">Introduction</h2>
</section>
<section>
<h2 id="usage">Usage</h2>
</section>
<section>
<h2 id="accessibility">Accessibility</h2>
</section> In Svelte, use NavScrollspy with a children snippet holding the <Ol> of links. It accepts labelHeader (the heading text, default On this page
), labelId, and is (default ds-scrollspy).
Accessibility
- The active link receives
aria-current="true"and it is removed from the others, so assistive technology announces the section currently in view. - The navigation is labelled with
aria-labelledbypointing at itsOn this page
heading, making it identifiable in a list of landmarks. - Links are real in-page anchors, so they are keyboard focusable and operable with or without the script — the highlight is an enhancement, never a requirement for navigation.
- Several links can be current at once when short sections share the top half of the viewport.
References
- Pure CSS scroll-driven Scrollspy(opens in new tab) — Sara Soueidan
- Table of Contents in Long-Form Content(opens in new tab) — Nielsen Norman Group
- Can I use: scroll-target-group(opens in new tab) — baseline tracking for the native replacement
Related
- Documentation — the two column layout that hosts the scrollspy in its aside
- Links — the underlying in-page anchor pattern
Variables
labelHeaderlabelIdis