rehype plugin to generate table of contents (TOC)
This package is a unified (rehype) plugin to generate a table of contents for a markdown document.
This project is useful when authors are writing docs in markdown that are sometimes quite long and hence would benefit from automated overviews inside them. It is assumed that headings define the structure of documents and that they can be linked to. When this plugin is used, authors can add a certain heading (say, ## Contents
) to documents and this plugin will populate those sections with lists that link to all following sections.
GitHub and similar services automatically add IDs (and anchors that link-to-self) to headings. For this plugin to work, you'll have to do something similar by using @microflash/rehype-slugify
before this plugin. To add anchors that link to headings, you can use rehype-autolink-headings
.
This plugin does not expose the generated table of contents to other plugins.
This package is ESM only.
In Node.js (version 12.20+, 14.14+, or 16.0+), install with npm:
npm install @microflash/rehype-toc
In Deno, with esm.sh:
import rehypeToc from 'https://esm.sh/@microflash/rehype-toc'
In browsers, with esm.sh:
<script type="module">
import rehypeToc from 'https://esm.sh/@microflash/rehype-toc?bundle'
</script>
Say we have the following file example.md
:
# Alpha
[[toc]]
## Bravo
### Charlie
## Delta
And our module example.js
looks as follows:
import Slugger from 'github-slugger'
import { read } from 'to-vfile'
import { rehype } from 'rehype'
import rehypeSlugify from '@microflash/rehype-slugify'
import rehypeToc from '@microflash/rehype-toc'
const slugger = new Slugger()
main()
async function main() {
const file = await rehype()
.data('settings', { fragment: true })
.use(rehypeSlugify, {
reset() {
slugger.reset()
},
slugify(text) {
return slugger.slug(text)
}
})
.use(rehypeToc)
.process(await read('example.md'))
console.log(String(file))
}
Running that with node example.js
yields:
<h1 id="alpha">Alpha</h1>
<details class="toc" id="table-of-contents">
<summary>Table of contents</summary>
<ul class="toc-items">
<li class="toc-item-1"><a href="#alpha">Alpha</a></li>
<li class="toc-item-2"><a href="#bravo">Bravo</a></li>
<li class="toc-item-3"><a href="#charlie">Charlie</a></li>
<li class="toc-item-2"><a href="#delta">Delta</a></li>
</ul>
</details>
<h2 id="bravo">Bravo</h2>
<h3 id="charlie">Charlie</h3>
<h2 id="delta">Delta</h2>
The default export is rehypeToc
.
The following options are available. All of them are optional.
matcher
(default:[[toc]]
): regex to match a node which can be replaced with table of contents. It can be any expression thathast-util-find-and-replace
can accept.id
(default:table-of-contents
): theid
of the TOC wrapper.toc(headings)
: function that returns table of contents as HAST.headings
array is available to customize the HAST the way you want. The default implementation generates a<details>
element with the headings as a flat unordered list.
Use of @microflash/rehype-toc
can open you up to a cross-site scripting (XSS) attack as it uses id
attributes on headings.
remark-toc
— opinionated plugin to generate a table of contents@microflash/rehype-slugify
— plugin to addid
s to headings using a slugger of your choicerehype-autolink-headings
— add links to headings with IDs back to themselves