tableOfContents
Install
Package manager
Import the theme
The cascade
Tokens
Pass the page’s headings and the rail tracks which of them are on screen, moving its indicator and marking the active link as the reader scrolls.
<TableOfContents
items={[
{ value: "install", depth: 2, label: "Install" },
{ value: "peer-dependencies", depth: 3, label: "Peer dependencies" },
{ value: "the-cascade", depth: 2, label: "The cascade" },
]}
/>
<TableOfContents
:items="[
{ value: 'install', depth: 2, label: 'Install' },
{ value: 'peer-dependencies', depth: 3, label: 'Peer dependencies' },
{ value: 'the-cascade', depth: 2, label: 'The cascade' },
]"
/>
The rail on the right of this page is this component, reading the headings this page generated.
Items
value is the id of the heading element on the page, not a slug of the label. It is
resolved with getElementById to know what is on screen, and the link targets it with a
hash, so an entry whose id is not on the page renders but never activates. Ids are
global to a document, so prefix them when one page holds more than one rail.
depth is the heading level as a number: 2 for an h2, 3 for an h3. Indentation is
styled off the data-depth attribute rather than declared as a variant, because one
list holds headings at several levels and a variant resolves once for the whole
component. Levels past four share the deepest indent rather than marching off the edge.
What it watches
By default the rail watches the page. Pass scrollEl when the prose scrolls inside a
panel instead, and rootMargin to move the line at which a heading starts counting as
read.
<TableOfContents items={items} scrollEl={() => panelRef.current} />
<TableOfContents :items="items" :scroll-el="() => panel" />
Slots
The same word names the recipe slot, the data-slot attribute and the key in ui.
- base
- nav
- title
- list
- indicator
- item
- link
Variants
Read off the recipe, so these are the values that actually resolve. A Theme layer can change which one is the default; it cannot add a value.
- color
- primarysecondarysuccessinfowarningerrorneutral
- size
- smmdlg
Props
Taken by both adapters, read out of the component module. The same names and the same types work in React and Vue.
- ui
TableOfContentsUI
Per-slot class overrides.
- color
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
Defaults to
"primary"- size
"sm" | "md" | "lg"
Defaults to
"md"- itemsrequired
TableOfContentsItem[]
The headings to list, in document order.
- title
string
Heading above the rail.
Defaults to
"On this page"- defaultActiveIds
string[]
Which headings count as active up front, before anything has scrolled.
- rootMargin
string
The `IntersectionObserver` margin deciding when a heading counts as read.
- autoScroll
boolean
Scroll the rail itself so the active entry stays visible.
Defaults to
true
Vue only
- class
unknown
- activeIds
string[]
- scrollEl
() => HTMLElement | null
The scrolling element to watch. Defaults to the page itself, which is what a documentation page wants; pass one when the prose scrolls inside a panel.