← Hub · Open the note

Table of contents (TOC) + scroll spy — demo — BEFORE/AFTER

Goal: when the user scrolls, show the current section in the TOC without color-only cues, and without stealing focus.

Try it

Scroll inside each panel’s content area. In the AFTER panel, the TOC updates the “current section” marker as you scroll.

Note: if you prefer reduced motion, smooth scrolling is automatically disabled.

BEFORE TOC link styling is color-only, and the TOC doesn’t track scroll position.

Overview

A table of contents should help you orient yourself, not distract you.

Scroll a bit. Notice the TOC doesn’t update when your reading position changes.

Setup

Each section has an id, and the TOC links to it.

But the UI doesn’t say which section is “current”.

Checklist

  • Works with keyboard and screen readers
  • Doesn’t rely on color only
  • Respects reduced motion

Edge cases

Long pages, deep heading nesting, sticky headers, and tiny viewports.

Without a scroll spy, users can lose their place.

Wrap-up

Now compare with the AFTER panel.

Failure modes: color-only “active”, no aria-current, no scroll tracking.

AFTER TOC uses aria-current + redundant styling, and updates as you scroll.

Overview

The TOC shows the current section while you scroll, without stealing focus.

Try clicking a TOC entry, then press Tab. If focus-move is enabled, focus lands on the heading (so keyboard users can continue reading).

Setup

Use stable heading ids. Keep TOC links as normal anchors.

When section changes, set aria-current="true" on the active TOC link.

Checklist

  • Active section marker is not color-only (shape + border + caret)
  • aria-current reflects the current section
  • Optional: polite “Section: …” announcements (avoid chatter)
  • Respect prefers-reduced-motion for smooth scrolling

Edge cases

Sticky headers? Add scroll-margin-top or scroll-padding-top.

If IntersectionObserver isn’t available, you can fall back to a throttled scroll handler.

Wrap-up

That’s the whole pattern: anchors + an optional scroll spy that updates aria-current.

Key difference: scroll spy updates TOC state and uses aria-current + redundant visuals.