Table of contents
@xui/tocThe in-page outline: a list of the document's headings, with the one being read marked. The links are plain fragment hrefs, so it needs no router and works on a prerendered page with no JavaScript; what JavaScript adds is the highlight, from an IntersectionObserver over the real headings.
Install
pnpm add @xui/toc Add the barrel to a standalone component's imports:
import { XuiTocImports } from '@xui/toc';@Component({ imports: [XuiTocImports], // …})Examples
Default
Loading preview…
<xui-toc [entries]="entries" size="md" [minLevel]="2" [maxLevel]="3" label="On this page" [scrollSpy]="false" class="w-56" />With an active entry
Loading preview…
<xui-toc [entries]="entries" size="md" [minLevel]="2" [maxLevel]="3" label="On this page" [scrollSpy]="false" activeId="using-it" class="w-56" />Deeper levels
Loading preview…
<xui-toc [entries]="entries" size="md" [minLevel]="2" [maxLevel]="4" label="On this page" [scrollSpy]="false" class="w-56" />No heading
Loading preview…
<xui-toc [entries]="entries" [label]="null" size="md" [minLevel]="2" [maxLevel]="3" [scrollSpy]="false" class="w-56" />Scroll spy
Loading preview…
<div class="flex gap-8"> <article xuiProse class="h-96 flex-1 overflow-y-auto"> <h2 xuiProseAnchor="what-it-is">What it is</h2> <p class="h-64">Scroll me.</p> <h2 xuiProseAnchor="what-it-is-for">What it is for</h2> <p class="h-64">Keep going.</p> <h2 xuiProseAnchor="using-it">Using it</h2> <p class="h-64">Nearly there.</p> <h2 xuiProseAnchor="examples">Examples</h2> <p class="h-64">The end.</p> </article> <xui-toc [entries]="entries" size="md" [minLevel]="2" [maxLevel]="3" label="On this page" [scrollSpy]="true" class="w-56 shrink-0 self-start" /></div>API
The in-page outline: a list of the document's headings, with the one you are reading marked.
Variants
sizemdInputs
classClassValueExtra classes, merged into the component's own rather than replacing them.''entriesreadonly XuiTocEntry[]The document's headings, in document order.[]activeIdstring | nullThe heading being read. Two-way bindable; scroll-spy writes it, and setting it from outside — from a route fragment, say — moves the highlight.nullminLevelnumberShallowest heading level to list. <h1> is the page title, so the default starts at <h2>.2maxLevelnumberDeepest heading level to list. Past <h3> an outline is longer than the page.3labelstring | nullHeading above the list. null hides it; the nav keeps its accessible name either way.'On this page'aria-labelstring | nullAccessible name for the nav landmark. Defaults to label, which is usually the right answer.nullscrollSpybooleanFollow the scroll position. Turn it off when something else owns activeId.truerootMarginstringThe band a heading has to be in to count as current, as an IntersectionObserver root margin. The default ignores the bottom 70% of the viewport, so the current section is the one at the top of the screen rather than whichever is merely visible.'0px 0px -70% 0px'basePathstring | nullPath the fragments hang off. Defaults to the page the outline is describing. Not a bare #id, which resolves against the document's base URL: an Angular application ships <base href="/">, so every entry on every page but the root would quietly point at the site root instead of down the page.nullsizeXuiTocVariants['size']Type scale of the outline.this.config.sizeOutputs
entrySelectedXuiTocEntryEmits the entry whose link was clicked. The navigation itself is the browser's.