astro-toc-smol
An Astro integration that generates an “On This Page” table of contents by scanning the final rendered HTML at build time. Includes a scroll spy script that highlights the active section as the user scrolls.
Installation
$ npm install astro-toc-smol
Setup
Register the integration
In astro.config.ts:
import tocSmol from 'astro-toc-smol';
export default defineConfig({
integrations: [
tocSmol({
articleSelector: ['article.prose', 'main'],
}),
],
});
Place the TOC component
In your layout, add the <TOC> component where you want the table of contents to appear.
Wrap it in a [data-toc-aside] element — the component hides the wrapper when the TOC is empty.
---
import TOC from 'astro-toc-smol/TOC.astro';
---
<aside data-toc-aside>
<p>On This Page</p>
<TOC />
</aside>
Integration options
| Option | Type | Default | Description |
|---|---|---|---|
articleSelector | string[] | ['article', 'main'] | CSS selectors tried in order to find the content area |
TOC component props
| Prop | Type | Default | Description |
|---|---|---|---|
maxDepth | number | 4 | Maximum heading depth to include (h2=2, h3=3, …) |
class | string | — | Additional CSS classes on the TOC container |
How it works
The integration hooks into astro:build:done and walks every .html file in the output.
For each file, it finds the content area matching articleSelector, extracts headings,
and injects a nested <ol> into the [data-server-toc] element the <TOC> component rendered.
The scroll spy script runs in the browser and updates aria-current="true" on the active
TOC link as the user scrolls.
If a page has no headings, the TOC is empty and the [data-toc-aside] wrapper is hidden
via JavaScript on DOMContentLoaded.