DEV Community

Cover image for How to Generate Table of Contents From Markdown/Html Text in Next.js
TnvMadhav⚡
TnvMadhav⚡

Posted on • Originally published at tnvmadhav.me

How to Generate Table of Contents From Markdown/Html Text in Next.js

Introduction

I wanted a programmatic way to generate and extract 'Table of Contents' HTML snippet from existing markdown text for my Next.js blogging website www.notionworkspaces.com.1

- These are the benefits of this approach:

  1. You don't have to have a Table of Contents section in all your markdown files or HTML files
  2. You can cut-out/extract (or) keep the table of contents after generating them in the content HTML using cheerio

In this tutorial, I'll teach you about a programmatic way to generate and extract 'Table of Contents' HTML snippet from existing markdown text in Next.js

TLDR; working code snippet here

Original Snippet before modification

I already had a function that converted markdown text to html text using remark2 library.

export async function getPostData(id) {
  const fullPath = path.join(postsDirectory, `${id}.md`);
  const fileContents = fs.readFileSync(fullPath, 'utf8');

  // Use gray-matter to parse the post metadata section
  const matterResult = matter(fileContents);

  // Use remark to convert markdown into HTML string
  const processedContent = await remark()
    .use(html)
    .process(matterResult.content);
  const contentHtml = processedContent.toString();

  // Combine the data with the id and contentHtml
  return {
    id,
    contentHtml,
    ...matterResult.data,
  };
}
Enter fullscreen mode Exit fullscreen mode

This above snippet was taken from the Next.js's official getting started tutorial3.

- What I wanted exactly:

But, it didn't do everything that I wanted. It didn't generate table of contents based on the structure of markdown data.

I googled around and found an existing library called remark-toc4 but it didn't do exactly what I wanted.

It required a few conditions that I didn't want to entertain.

I later stumbled upon rehype5 library a more recent take on processing html (also markdown) in Next.js.

The Working Code Snippet

This is final code I use to generate and extract table of contents from my markdown content.

export async function getPostData(id) {
  const fullPath = path.join(postsDirectory, `${id}.md`);
  const fileContents = fs.readFileSync(fullPath, 'utf8');

  // Use gray-matter to parse the post metadata section
  const matterResult = matter(fileContents);

  const file = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeSlug)
  .use(rehypeDocument)
  .use(rehypeFormat)
  .use(rehypeTOC)
  .use(rehypeStringify)
  .process(matterResult.content)

  // Extract TOC dynamically
  const $ = cheerio.load(String(file));
  const contentTOC = $("nav.toc").html();
  $("nav.toc").remove();
  const contentHtml = $.html();

  // Combine the data with the id and contentHtml
  return {
    id,
    contentHtml,
    contentTOC,
    ...matterResult.data,
  };
}
Enter fullscreen mode Exit fullscreen mode

I used the following imports to get it all working seamlessly,

The import requirements

import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeDocument from 'rehype-document'
import rehypeFormat from 'rehype-format'
import rehypeStringify from 'rehype-stringify'
import rehypeSlug from 'rehype-slug'
import rehypeTOC from "@jsdevtools/rehype-toc";
import * as cheerio from 'cheerio';
Enter fullscreen mode Exit fullscreen mode

I used cheerio6 to build an DOM tree from html text for me to extract the TOC div component using the name nav.tov and use it as a Table of Contents snippet I used in my react components.

This is a screenshot of how I used this piece of code on www.notionworkspaces.com.

A screenshot of https://notionworkspaces.com/ website

The dynamic table of contents section, in left section in the above screenshot.

I hope you found this useful!

👋 -- @TnvMadhav

References


  1. Notion Workspaces -- Discover Amazing Notion Workspaces 

  2. Remark -- Tool that transforms markdown with plugins 

  3. Next.js -- Offical Getting Started 

  4. RemarkTOC -- Remark plugin to generate a table of contents 

  5. ReHype -- Tool that transforms HTML with plugins 

  6. Cheerio -- Fast, flexible & lean implementation of core jQuery designed specifically for the server 

Top comments (0)