@jsdevtools/rehype-toc
Version:
A rehype plugin that adds a table of contents (TOC) to the page
276 lines (205 loc) • 11.4 kB
Markdown
# Table of Contents plugin for Rehype
A [rehype](https://github.com/rehypejs/rehype) plugin that adds a table of contents (TOC) to the page
[](https://github.com/JS-DevTools/rehype-toc/actions)
[](https://github.com/JS-DevTools/rehype-toc/actions)
[](https://coveralls.io/github/JS-DevTools/rehype-toc)
[](https://david-dm.org/JS-DevTools/rehype-toc)
[](https://www.npmjs.com/package/@jsdevtools/rehype-toc)
[](LICENSE)
[](https://plant.treeware.earth/JS-DevTools/rehype-toc)
Features
--------------------------
- Adds a `<nav>` and `<ol>` list outlining all headings on the page
- Combine with [rehype-slug](https://github.com/rehypejs/rehype-slug) to create links to each heading
- Ignores headings outside of `<main>` if it exists
- You can customize which headings are included (defaults to `<h1>` - `<h6>`)
- You can customize the CSS classes on every TOC element
- Hooks give you complete customization of the generated HTML
Example
--------------------------
**input.html**<br>
Here's the original HTML file. There are three levels of headings (`<h1>` - `<h3>`), and none of them have IDs.
```html
<html>
<body>
<h1>Apple Pie Recipe</h1>
<p>This is the world's best apple pie recipe...</p>
<div>
<h2>Filling</h2>
<p>The filling is the best part...</p>
<h3>Preparing the apples</h3>
<p>Cut the apples into 1/4 inch slices...</p>
<h3>Preparing the spice mix</h3>
<p>In a mixing bowl, combine sugar, cinnamon...</p>
</div>
<div>
<h2>Crust</h2>
<p>How to make the perfect flaky crust...</p>
<h3>Preparing the dough</h3>
<p>Combine flour, sugar, salt...</p>
<h3>The criss-cross top</h3>
<p>Cut the top crust into 1/2 inch strips...</p>
</div>
</body>
</html>
```
**example.js**<br>
This script reads the `input.html` file above writes the results to `output.html` (shown below). The script uses [unified](https://unifiedjs.com/), [rehype-parse](https://github.com/rehypejs/rehype/tree/master/packages/rehype-parse), [rehype-slug](https://github.com/rehypejs/rehype-slug), and [rehype-stringify](https://github.com/rehypejs/rehype/tree/master/packages/rehype-stringify).
```javascript
const unified = require("unified");
const parse = require("rehype-parse");
const slug = require("rehype-slug");
const toc = require("@jsdevtools/rehype-toc");
const stringify = require("rehype-stringify");
const fs = require("fs");
async function example() {
// Create a Rehype processor with the TOC plugin
const processor = unified()
.use(parse)
.use(slug)
.use(toc)
.use(stringify);
// Read the original HTML file
let inputHTML = await fs.promises.readFile("input.html");
// Process the HTML, adding heading IDs and Table of Contents
let outputHTML = await processor.process(inputHTML);
// Save the new HTML
await fs.promises.writeFile("output.html", outputHTML);
}
```
**output.html**<br>
Here's the HTML that gets created by the above script. Notice that a table of contents has been added at the top of the `<body>`, with links to each of the headings on the page. The headings also now have IDs, thanks to [rehype-slug](https://github.com/rehypejs/rehype-slug).
```html
<html>
<body>
<nav class="toc">
<ol class="toc-level toc-level-1">
<li class="toc-item toc-item-h1">
<a class="toc-link toc-link-h1" href="#apple-pie-recipe">
Apple Pie Recipe
</a>
<ol class="toc-level toc-level-2">
<li class="toc-item toc-item-h2">
<a class="toc-link toc-link-h2" href="#filling">
Filling
</a>
<ol class="toc-level toc-level-3">
<li class="toc-item toc-item-h3">
<a class="toc-link toc-link-h3" href="#preparing-the-apples">
Preparing the apples
</a>
</li>
<li class="toc-item toc-item-h3">
<a class="toc-link toc-link-h3" href="#preparing-the-spice-mix">
Preparing the spice mix
</a>
</li>
</ol>
</li>
<li class="toc-item toc-item-h2">
<a class="toc-link toc-link-h2" href="#crust">
Crust
</a>
<ol class="toc-level toc-level-3">
<li class="toc-item toc-item-h3">
<a class="toc-link toc-link-h3" href="#preparing-the-dough">
Preparing the dough
</a>
</li>
<li class="toc-item toc-item-h3">
<a class="toc-link toc-link-h3" href="#the-criss-cross-top">
The criss-cross top
</a>
</li>
</ol>
</li>
</ol>
</li>
</ol>
</nav>
<h1 id="apple-pie-recipe">Apple Pie Recipe</h1>
<p>This is the world's best apple pie recipe...</p>
<div>
<h2 id="filling">Filling</h2>
<p>The filling is the best part...</p>
<h3 id="preparing-the-apples">Preparing the apples</h3>
<p>Cut the apples into 1/4 inch slices...</p>
<h3 id="preparing-the-spice-mix">Preparing the spice mix</h3>
<p>In a mixing bowl, combine sugar, cinnamon...</p>
</div>
<div>
<h2 id="crust">Crust</h2>
<p>How to make the perfect flaky crust...</p>
<h3 id="preparing-the-dough">Preparing the dough</h3>
<p>Combine flour, sugar, salt...</p>
<h3 id="the-criss-cross-top">The criss-cross top</h3>
<p>Cut the top crust into 1/2 inch strips...</p>
</div>
</body>
</html>
```
Installation
--------------------------
You can install Rehype TOC via [npm](https://docs.npmjs.com/about-npm/).
```bash
npm install @jsdevtools/rehype-toc
```
You'll probably want to install [unified](https://unifiedjs.com/), [rehype-parse](https://github.com/rehypejs/rehype/tree/master/packages/rehype-parse), [rehype-stringify](https://github.com/rehypejs/rehype/tree/master/packages/rehype-stringify), and [rehype-slug](https://github.com/rehypejs/rehype-slug) as well.
```bash
npm install unified rehype-parse rehype-stringify rehype-slug
```
Usage
--------------------------
Using the Rehype TOC plugin requires an understanding of how to use Unified and Rehype. [Here is an excelleng guide](https://unifiedjs.com/using-unified.html) to learn the basics.
The Rehype TOC plugin works just like any other Rehype plugin. Pass it to [the `.use()` method](https://github.com/unifiedjs/unified#processoruseplugin-options), optionally with an [options object](#options).
```javascript
const unified = require("unified");
const toc = require("@jsdevtools/rehype-toc");
// Use the Rehype TOC plugin with its default options
unified().use(toc);
// Use the Rehype TOC plugin with custom options
unified().use(toc, {
headings: ["h1", "h2"], // Only include <h1> and <h2> headings in the TOC
cssClasses: {
toc: "page-outline", // Change the CSS class for the TOC
link: "page-link", // Change the CSS class for links in the TOC
}
});
```
Options
--------------------------
The Rehype TOC plugin supports the following options:
|Option |Type |Default |Description
|:---------------------|:-------------------|:----------------------|:-----------------------------------------
|`nav` |boolean |true |Determines whether the table of contents is wrapped in a `<nav>` element.
|`position` |string |"afterbegin" |The position at which the table of contents should be inserted, relative to the `<main>` or `<body>` element. Can be "beforebegin", "afterbegin", "beforeend", or "afterend". See [the `insertAdjacentElement()` docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentElement) for an explanation of each value.
|`headings` |array of strings |h1, h2, h3, h4, h5, h6 |The HTML heading tags to include in the table of contents
|`cssClasses.toc` |string |toc |The CSS class name for the top-level `<nav>` or `<ol>` element that contains the whole table of contents.
|`cssClasses.list` |string |toc-level |The CSS class name for all `<ol>` elements in the table of contents, including the top-level one.
|`cssClasses.listItem` |string |toc-item |The CSS class name for all `<li>` elements in the table of contents.
|`cssClasses.link` |string |toc-link |The CSS class name for all `<a>` elements in the table of contents.
|`customizeTOC` |function(toc) | |Allows you to customize the table of contents before it is added to the page.<br><br>The function receives the TOC node tree and can modify it in any way you want. Or you can return a new node tree to use instead. Or return `false` to prevent the the TOC from being added to the page.
|`customizeTOCItem` |function(toc, heading)| |Allows you to customize each item in the table of contents before it is added to the page.<br><br>The function receives the TOC item's node tree and the heading node that it refers to. You can modify the nodes in any way you want. Or you can return a new node tree to use instead. Or return `false` to prevent the the TOC from being added to the page.
Contributing
--------------------------
Contributions, enhancements, and bug-fixes are welcome! [Open an issue](https://github.com/JS-DevTools/rehype-toc/issues) on GitHub and [submit a pull request](https://github.com/JS-DevTools/rehype-toc/pulls).
#### Building
To build the project locally on your computer:
1. __Clone this repo__<br>
`git clone https://github.com/JS-DevTools/rehype-toc.git`
2. __Install dependencies__<br>
`npm install`
3. __Build the code__<br>
`npm run build`
4. __Run the tests__<br>
`npm test`
License
--------------------------
Rehype TOC is 100% free and open-source, under the [MIT license](LICENSE). Use it however you want.
This package is [Treeware](http://treeware.earth). If you use it in production, then we ask that you [**buy the world a tree**](https://plant.treeware.earth/JS-DevTools/rehype-toc) to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.
Big Thanks To
--------------------------
Thanks to these awesome companies for their support of Open Source developers ❤
[](https://travis-ci.com)
[](https://saucelabs.com)
[](https://coveralls.io)