Toc
An on-this-page table of contents that highlights the section currently in view.
Live demo
Toc lists the sections of a page as in-page links and tracks which one the reader is looking at. Give it items: each is an id matching a section's element id plus a label, and it renders a labelled nav of anchor links.
An IntersectionObserver then marks the active link as you scroll, setting aria-current and the accent rail. The links work as plain anchor jumps with no script, so the scrollspy is pure progressive enhancement. It reads as a vertical rail beside the content and folds into a wrapped row of chips on narrow screens. Pass sticky to keep it in view as the page scrolls.
When to use
How this component composes with the rest of the set.
Props
3 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
Appearance
States
active
The link for the section currently in view: accent ink and rail, set alongside aria-current.
focus-visible
Keyboard focus on a link: a token ring plus a transparent outline that becomes real in forced-colors mode.
Anatomy
The named parts that make up the component, with their selectors.
toc
The nav root carrying the rail border and (optional) sticky positioning.
label
The small uppercase heading above the list.
link
A section link with its accent rail when active and a focus ring.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xoji-default register
(derive(xojiDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent
--accent-bg
--accent-text
--bg-1
--border-normal
--border-thick
--border-thin
--duration-fast
--ease-standard
--fg-0
--fg-2
--font-sans
--line
--radius-md
--radius-sm
--ring
--space-1
--space-2
--space-3
--space-5
--text-sm
--text-xs
--weight-medium
--weight-semibold
Accessibility
Code
A scrollspy table of contents
A sticky rail of section links that tracks the section in view; on narrow screens it folds into a wrapped row.
<xoji-toc
label="On this page"
sticky
items='[{"id":"intro","label":"Intro"},{"id":"usage","label":"Usage"},{"id":"api","label":"API"}]'
></xoji-toc>
<script lang="ts">
import { Toc } from "@xoji/svelte";
const items = [
{ id: "intro", label: "Intro" },
{ id: "usage", label: "Usage" },
{ id: "api", label: "API" },
];
</script>
<Toc {items} label="On this page" sticky />
---
import { Toc } from "@xoji/astro";
const items = [
{ id: "intro", label: "Intro" },
{ id: "usage", label: "Usage" },
{ id: "api", label: "API" },
];
---
<Toc items={items} label="On this page" sticky />