@mattbal/rehype-toc
TypeScript icon, indicating that this package has built-in type declarations

3.3.3 • Public • Published

Table of Contents plugin for Rehype

A rehype plugin that adds a table of contents (TOC) to the page.

This plugin is a fork from JS-DevTools/rehype-toc. See the list of differences below.

npm

Features

  • Create an <ol> list outlining all headings on the page
  • Combine with 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

What's the difference between this and JS-DevTools/rehype-toc ?

  • This plugin is a fork of JS-DevTools/rehype-toc that is more up to date.
  • I updated all of the original dependencies to their latest version and removed some of the extra, excess dependencies to make this project lighter.
  • This plugin has no security vulnerabilities. The original, JS-DevTools/rehype-toc, had several because the dependencies weren't being updated.
  • I added a suffix option, in case you want neater CSS classname outputs.
  • I fixed over a dozen TypeScript errors in the original project.

Example

input.html
Here's the original HTML file. There are three levels of headings (<h1> - <h3>), and none of them have IDs.

<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
This script reads the input.html file above writes the results to output.html (shown below). The script uses unified, rehype-parse, rehype-slug, and rehype-stringify.

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
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.

<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>

NextJS Example with MDX-remote

const root = process.cwd();
let fileContents = fs.readFileSync(join(root, 'posts', `${slug}.mdx`), 'utf8');

const source = await serialize(fileContents, {
  parseFrontmatter: true,
  mdxOptions: {
    remarkPlugins: [remarkGfm],
    rehypePlugins: [
      rehypeSlug,
      [toc, {
        nav: false,
        suffix: false,
      }]
    ]
  }
})

Installation

You can install Rehype TOC via npm.

npm install @mattbal/rehype-toc

You'll probably want to install unified, rehype-parse, rehype-stringify, and rehype-slug as well.

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 excellent guide to learn the basics.

The Rehype TOC plugin works just like any other Rehype plugin. Pass it to the .use() method, optionally with an options object.

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 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
suffix boolean true When enabled, <ol> elements will be appended with their depth level and <li> and <a> elements will be appended with their heading size, e.g., <ol class="toc-level toc-level-1"> and <a class="toc-link toc-link-h1">. However, if use a custom TailwindCSS string for the cssClasses property, this will result in a string like "font-normal text-gray-500" being transformed into "font-normal text-gray-500-h2". To use a multi-class string like TailwindCSS for the cssClasses option, set suffix to false.
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.

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.

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 on GitHub and submit a pull request.

Building

To build the project locally on your computer:

  1. Clone this repo
    git clone https://github.com/mattbal/rehype-toc.git

  2. Install dependencies
    npm install

  3. Build the code
    npm run build

Note: Every time you change a TypeScript file in the project, you will have to run npm run build again to re-compile the project.

  1. Run the tests
    npm test

Testing it before contributing

Inside the rehype-toc folder, run in terminal npm link. Then inside of another web application you want to test it in, npm link @mattbal/rehype-toc.

To remove the link, run npm r @mattbal/rehype-toc -g. (To see all of your global NPM packages you can run npm ls -g in case you aren't sure whether the link is there.)

License

Rehype TOC is 100% free and open-source, under the MIT license. Use it however you want.

Package Sidebar

Install

npm i @mattbal/rehype-toc

Weekly Downloads

3

Version

3.3.3

License

MIT

Unpacked Size

50 kB

Total Files

36

Last publish

Collaborators

  • mattbal