/// Navigation
TableOfContents
A page nav auto-built from headings, with scrollspy active-highlighting — the reusable docs rail.
import { TableOfContents } from "@protocore/pds";Explicit headings
Pass a headings array of { id, text, level }. Each renders as a real anchor to #id, indented by level. As the reader scrolls, the entry for the section in view highlights via scrollspy.
Overview
Section content for overview. Scroll the page to watch the rail track the heading in view.
Installation
Section content for installation. Scroll the page to watch the rail track the heading in view.
Configuration
Section content for configuration. Scroll the page to watch the rail track the heading in view.
Deploying
Section content for deploying. Scroll the page to watch the rail track the heading in view.
Scanning the DOM
Omit headings and the component scans the page for you: give it a containerSelector (default "main") and a selector (default "h2, h3"), and it collects every matching heading that has an id. This is the mode to pair with Prose — render your CMS/markdown content (whose headings already carry slugged ids), drop a TableOfContents beside it, and the rail builds itself.
The anchors are ordinary links, so the rail works with JavaScript disabled; the IntersectionObserver only drives the active-highlight. Clicking smooth-scrolls to the target and moves keyboard focus there. Tune offset to match any sticky header so the active section flips at the right moment.
Usage
Do
- Ensure every target heading has a stable `id` to anchor to.
- Use scan mode next to Prose-rendered content.
- Set `offset` to your sticky-header height for accurate spy timing.
- Keep it to two levels (h2/h3) so the rail stays scannable.
Don't
- Point entries at headings without ids; the anchor has nowhere to go.
- Nest four-plus levels; the rail becomes a thicket.
- Rebuild it from scroll math — it already uses an observer.
Accessibility
| Keys | Action |
|---|---|
| Tab | Moves through the table-of-contents links |
| Enter | Jumps to the section and moves focus there |
- Renders a `<nav>` landmark with an `aria-label`, and marks the active entry with `aria-current="location"`.
- Activating a link moves keyboard focus to the target heading (via a temporary `tabindex`), so the next Tab continues from the new section.
TableOfContents props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
containerSelector | string | main | CSS selector for the region to scan. |
headings | TocHeading[] | — | Explicit headings. Omit to scan the DOM via `containerSelector` + `selector`. |
label | string | Table of contents | Accessible name for the nav landmark. |
offset | number | 96 | Distance (px) from the top at which a heading becomes active. |
selector | string | h2, h3 | Which headings to collect when scanning. |
style | CSSProperties | — |