DEV Community

Cover image for Table of Content for MDX with Next.js
CY
CY

Posted on • Originally published at cyishere.dev

5 1

Table of Content for MDX with Next.js

I use Next.js & MDX for my personal website and some documents, I want to display a "table of content", a list of headings, for each article.

I've tried the plugin remark-toc but it's too complex (for me). I spend hours still couldn't make the toc work... So, I tried to write it by myself.

Get The List of Headings

Here's the code for getting the list of headings:

// ./components/PostLayout.js

import { renderToString } from "react-dom/server";
import { MDXProvider } from "@mdx-js/react";

import MDXComponents from "./MDXComponents";

const PostLayout = ({ children }) => {
  const contentString = renderToString(children);

  const getHeadings = (source) => {
    const regex = /<h2>(.*?)<\/h2>/g;

    if (source.match(regex)) {
      return source.match(regex).map((heading) => {
        const headingText = heading.replace("<h2>", "").replace("</h2>", "");

        const link = "#" + headingText.replace(/ /g, "_").toLowerCase();

        return {
          text: headingText,
          link,
        };
      });
    }

    return [];
  };

  const headings = getHeadings(contentString);

  return (
    <>
      {/* ... */}

      {headings.length > 0 ? (
        <ol>
          {headings.map((heading) => (
            <li key={heading.text}>
              <a href={heading.link}>{heading.text}</a>
            </li>
          ))}
        </ol>
      ) : null}

      <MDXProvider components={MDXComponents}>
        <Container>{children}</Container>
      </MDXProvider>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

Add IDs to Headings

I use the MDXProvider to render the Markdown content, then customize the components in a separated file.

Here's the customized h2:

// ./components/MDXComponents.js

const Heading2 = ({ children }) => {
  const idText = children.replace(/ /g, "_").toLowerCase();

  return <h2 id={idText}>{children}</h2>;
};

const MDXComponents = {
  h2: Heading2,
  // ...
};

export default MDXComponents;
Enter fullscreen mode Exit fullscreen mode

Now, everything works as I expected. I made a Next.js & MDX starter, click here to visit the repo could find the whole code.

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

👋 Kindness is contagious

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

Okay