<tc-toc>
Auto-built table of contents. Scans a target for headings and tracks the active section via IntersectionObserver.
Props
| Name | Type | Default | Description |
|---|---|---|---|
target | string | "main" | CSS selector for the content container to scan. |
levels | string | "h2,h3" | Comma-separated heading tags to include. |
sticky | boolean | true | Apply `position: sticky` so the TOC pins to the top while scrolling. |
label | string | "On this page" | Heading rendered above the list. |
CSS variables
| Variable | Default | Description |
|---|---|---|
--tc-toc-fg | var(--tc-color-ink, #14171f) | Hover color of TOC links. |
--tc-toc-fg-muted | var(--tc-color-ink-muted, #6b7280) | Resting link color. |
--tc-toc-active | var(--tc-color-accent, #a16939) | Active link color. |
--tc-toc-rule | var(--tc-color-rule, #ece5d3) | Left rule next to the list. |
--tc-toc-label | var(--tc-color-ink-soft, #4a5061) | Color of the "On this page" label. |
--tc-toc-font | var(--tc-font-sans, …) | Font family. |
--tc-toc-top | "80px" | Top offset when `sticky` is true. Set to your header height. |
Examples
Basic usage
Drop the component into your layout and point it at the article container.
The TOC will list every matching heading. Headings without an id get one assigned based on their text (the same slugify rule most docs sites use), so anchor links work without extra setup.
Heading levels
By default tc-toc matches h2 and h3. Add h4 if your articles run deep:
Only h2–h6 levels are styled with indent; deeper levels share h6 indent.
Custom label
Custom sticky offset
If you have a tall fixed header, set --tc-toc-top to match.
Non-sticky
Some layouts work better without sticky positioning — for example, when the TOC sits in the article's own flow.
Active section tracking
The component sets up an IntersectionObserver with rootMargin: "0px 0px -70% 0px" so a heading becomes "active" once it scrolls into roughly the top third of the viewport. There's no prop to tweak the trigger zone in this version — fork the source if you need custom logic.
Theming
Accessibility
- Rendered as a
<nav aria-label="Table of contents">— assistive tech announces it as navigation. - Links are real
<a href="#…">anchors, so keyboard users can Tab through them. - The IntersectionObserver runs only after mount, so server-rendered or static HTML works without flashing an empty TOC.
- The component never traps focus — clicking a link scrolls and focuses the heading per the browser's normal anchor behavior.