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 

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay