Table of Content (TOC)
A scroll-spy navigation sidebar that tracks the current section as the page scrolls.
Usage
Toc is an "on this page" sidebar that watches the document and highlights the link whose heading is currently in view. Each TocLink's href points at a heading's id (href="#installation" → <h2 id="installation">); the component registers those targets, observes them with an IntersectionObserver, and marks the visible ones data-active. When several headings share the screen the indicator stretches to cover the whole span, and aria-current lands on the topmost one.
It's purely compositional — no list data is passed in. Lay out the items yourself (typically generated from your page's headings) and set each link's depth to match its heading level so deeper headings indent. Everything is driven by the real DOM, so the headings just need matching ids.
Because scroll-spy needs a scroll position to track, the live examples below put the article in a self-contained scrolling panel — scroll inside it to watch the active link follow along. They also intercept link clicks to scroll that panel rather than the page; on a real page where the TOC tracks the document, you'd skip that and let the anchor jump the page natively.
Examples
Default
A flat list of top-level headings. As you scroll the article, the link tracking the visible heading lights up and the indicator slides to it.
Nested headings
Give each TocLink a depth (2–6) matching its heading level and deeper entries indent automatically — the typical <h2>/<h3> outline. The active indicator runs down the shared left rail regardless of depth.
With icons
TocLink takes arbitrary children, so you can prefix each entry with an icon. Set the link to flex and size the SVG; the icon inherits the link's color, so it brightens along with the label when active.
Scroll offset
On a real page with a sticky header, headings become "current" a little too early — they're technically in view but hidden behind the header. Pass rootMargin to Toc to shrink the observer's viewport from the top by the header's height, so a heading only counts as active once it clears it:
The value is a standard IntersectionObserver rootMargin string (top right bottom left). A negative top inset pulls the active boundary down below your header.
Router links
TocLink is built on Base UI's useRender, so you can project it onto your framework's link with render while keeping the scroll-spy wiring and active styling:
RTL
Every Appica UI component supports right-to-left layouts out of the box. Set the dir attribute on a container (commonly your <html> element) so CSS logical properties resolve correctly, and wrap your tree in DirectionProvider so direction-aware behavior follows the same direction.
The list's rail and active indicator move to the right edge and the depth indentation flips, since both are built from CSS logical properties. For setup details and caveats, see the RTL guide.
API reference
Each part forwards every remaining prop to its underlying element (nav, ul, li, a). The tables below list the Appica additions and the most common props.
Toc
The navigation landmark and scroll-spy provider. Renders a <nav aria-label="Table of contents">.
TocList
The list of entries, carrying the shared rail and sliding active indicator. Renders a <ul role="list">.
TocItem
One entry's <li> wrapper.
TocLink
A link to one heading. Registers its target for scroll-spy and reflects the active state. Built on Base UI's useRender; renders an <a> unless you project it with render.
The link exposes data-active while its heading is in view and aria-current="true" on the topmost active link — both available for styling.
Accessibility
Tocrenders a<nav>with a defaultaria-label="Table of contents"; override it (e.g."On this page") to suit the surrounding page. The list is arole="list"of plain links.- The topmost in-view link carries
aria-current="true", so assistive tech announces the reader's current position. - Links are ordinary anchors, fully keyboard-focusable, and activating one jumps to its heading — pair headings with
scroll-mt-*so they aren't hidden under a sticky header on arrival. - The active indicator and link transitions honour
prefers-reduced-motion. - Scroll-spy is presentational: it only updates
data-active/aria-current, never moving focus or scrolling on its own.