[rehype] 記事冒頭に見出しリンク(目次)を追加する

MDXの記事本文に対して、記事冒頭の目次見出しリンクを同時に付ける方法の記録。 next-mdx-remotecompileMDX している構成を前提にしている。

背景

長めの記事だと、冒頭で構成が分かった方が読みやすい。 そこで、rehypeで見出しを収集して目次を挿入し、各見出しにアンカーリンクも付ける。

環境

  • Next.js 16.0.7 (App Router)
  • TypeScript
  • next-mdx-remote 5.0.0
  • rehype-pretty-code 0.14.1
  • rehype-slug / rehype-toc / rehype-autolink-headings

実装方針

  • rehype-slug で見出しに id を付与
  • rehype-toc で見出し一覧を目次として挿入
  • rehype-autolink-headings で各見出しにリンクを付与

それぞれの役割(簡単に)

  • rehype-slug: 見出し要素(h2 など)に id を自動付与して、リンク先を作る
  • rehype-toc: 付与された id を使って目次(リンク一覧)を生成し、本文に差し込む
  • rehype-autolink-headings: 各見出しにアンカーリンクを追加し、見出し自体から移動できるようにする

実装手順

1. 依存パッケージを追加

yarn add rehype-slug rehype-toc rehype-autolink-headings

2. MDXのrehype設定を追加

lib/note.tsmdxOptions.rehypePlugins に追加する。 rehype-toc はデフォルトで記事先頭(afterbegin)に目次を挿入するため、 特別なオプション無しでも冒頭に出せる。

// lib/note.ts 抜粋
import rehypeSlug from "rehype-slug";
import rehypeToc from "rehype-toc";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
 
mdxOptions: {
  remarkPlugins: [remarkGfm],
  rehypePlugins: [
    rehypeSlug,
    rehypeToc,
    [rehypeAutolinkHeadings, { behavior: "append" }],
    [
      rehypePrettyCode,
      {
        theme: {
          light: "vitesse-light",
          dark: "vitesse-dark",
        },
        transformers: [transformerNotationDiff()],
      },
    ],
  ],
},

3. TOCに含める見出しを絞る(任意)

h2/h3 だけを対象にしたい場合は headings を指定する。

[rehypeToc, { headings: ["h2", "h3"], position: "afterbegin" }]

4. 見た目の調整(任意)

rehype-toc.toc / .toc-level / .toc-item / .toc-link などのクラスを出力するので、 必要に応じてスタイルを足す。

.markdown-body .toc {
  padding: 1rem 1.25rem;
  border: 1px solid color-mix(in srgb, var(--color-text) 20%, transparent);
  margin: 1rem 0 2rem;
  border-radius: 8px;
}
 
.markdown-body .toc-link {
  color: inherit;
  text-decoration: none;
}
 
.markdown-body .toc-link:hover {
  text-decoration: underline;
}

見出しリンク側にクラスを付けたい場合は properties を追加する。

[rehypeAutolinkHeadings, {
  behavior: "append",
  properties: { className: ["heading-anchor"] },
}]
.markdown-body .heading-anchor {
  margin-left: 0.4em;
  opacity: 0.5;
  text-decoration: none;
}
 
.markdown-body .heading-anchor:hover {
  opacity: 1;
}

まとめ

  • rehype-slugid を付与
  • rehype-toc で記事冒頭に目次を追加
  • rehype-autolink-headings で各見出しにリンクを付与

記事冒頭で構成が分かり、本文中の移動もしやすくなる。

参考リンク