Table of Contents
An anchor list that tracks which heading is on screen, through IntersectionObserver rather than scroll offsets. Reads the DOM by default, so it works for rendered markdown.
src/components/ui/table-of-contents.tsxAbout
From the component's own source, where it was written.
An anchor list that tracks which heading is on screen.
Scroll-spy through IntersectionObserver, not scroll offsets. Measuring positions on every scroll event means reading layout in a handler that fires dozens of times a second, and the browser already computes this.
The rootMargin pulls the detection band up to the top quarter of the viewport. Without it the active item is whatever is nearest the bottom, so the highlight sits one or two headings ahead of what you are reading.
Headings are found in the DOM rather than passed in, so it stays correct for content rendered from markdown where the caller has no list to give.
Install
npx astralyx-ui add table-of-contents
Usage
import { TableOfContents } from '@/components/ui/table-of-contents'
<TableOfContents selector="h2, h3" container="#doc" />Composer
Change the props and the source below follows.
<TableOfContents selector="h2, h3" label="On this page" />
Examples
Anchors
<TableOfContents selector="h2, h3" />
API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
TableOfContents
Extends ComponentProps<'nav'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| items | TocItem[] | — | Supply headings directly, or omit and let it read the DOM. |
| selector | string | 'h2, h3' | What to collect and where. Headings need ids. |
| container | string | 'h2, h3' | What to collect and where. Headings need ids. |
| label | string | 'On this page' | — |
Hooks
| Hook | Signature | Description |
|---|---|---|
| useHeadings | (selector: string, container?: string) => TocItem[] | Exported, for building your own list. |
Types
TocItem
An anchor list that tracks which heading is on screen.
| Field | Type | Description |
|---|---|---|
| id | string | — |
| label | string | — |
| level | number | — |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| scroll-spy | IntersectionObserver | The rootMargin pulls the detection band to the top quarter of the viewport — without it the highlight sits one or two headings ahead of what you are reading. |