Gatsbyの記事管理にMarkdownを使っているときに、任意の記事内に目次を追加して、さらにその飛び先として利用するためのアンカー設定を各見出しに追加する方法です。
全記事に自動追加したいとかマークアップを自分好みにしたい場合は自前で実装した方が良いですが、特にそういったものがなければプラグインを利用することで容易に実装できます。

紹介している内容はGatsby Ver 3.9.1を使用して動作確認したものになります。
また、使用するプラグインはいずれも「gatsby-transformer-remark」のサブプラグインとなります。

目次を追加

目次の追加には「gatsby-remark-table-of-contents」を利用します。

$ npm i gatsby-remark-table-of-contents

gatsby-config.jsには「gatsby-transformer-remark」のサブプラグインとして指定し、オプション指定なしの場合は下記のように記述します。

gatsby-config.js
plugins: [
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        `gatsby-remark-table-of-contents`,
      ],
    },
  },
],

あとは目次を追加したい記事に下記を記述すれば目次が追加されるのを確認できます。
単純に指定した場合はulを用いたリストが.tocというclassで括られる形で出力されるので、見栄えを整えたい際はそれらを利用します。

example.md
```toc
```

オプション設定

デフォルトでもそれっぽいものを実装できますが、下記のようにgatsby-config.jsでオプション指定することでより出力内容を好みに変更することできます。

gatsby-config.js
plugins: [
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        resolve: `gatsby-remark-table-of-contents`,
        options: {
          exclude: `example`,
          tight: true,
          ordered: true,
          fromHeading: 2,
          toHeading: 4,
          className: `example-toc`,
        },
      ],
    },
  },
],
  • exclude
    文字列を指定することで該当の見出しを目次から除外することができ、上のサンプルコードの場合は「example」という文字列の見出しは目次から除外できます。
    また、複数の文字列を除外対象にしたいときはexclude: [`foo`, `bar`, `baz`]のように配列で指定します。
  • tight
    デフォルトではa要素をp要素で括られているのが、tight: trueにすることでp要素がないul > li > aのような構造になります。
  • ordered
    デフォルトはul要素になっているのが、ordered: trueにすることでol要素になります。
  • fromHeading, toHeading
    fromHeadingで対象の最小見出しレベルを、toHeadingで対象の最大見出しレベルをそれぞれ指定でき、デフォルトではh2h6までの見出しが対象ですが、上のサンプルコードのように記述することでh2h4までが対象となります。
  • className
    デフォルトでは目次要素を括っている要素に.tocというclassが指定されていますが、それを任意のclassに変更でき、上のサンプルコードの場合は目次を括る要素のclass名が.example-tocに変更されます。

記事毎にオプションを変更

オプションはgatsby-config.jsで指定するだけでなく、特定記事にのみ異なるオプションを指定することもできます。
その場合は目次を追加する際のコードブロック内に指定し、例えば下記は「Lorem ipsum」という見出しは目次から除外しつつ、対象の見出しレベルがh3h5になります。

example.md
```toc
exclude: Lorem ipsum
fromHeading: 3
toHeading: 5
```

見出しにアンカー設定を追加

上で目次が表示されるようになったら、次は飛び先である各見出しにアンカー設定を「gatsby-remark-autolink-headers」を利用して追加していきます。

$ npm i gatsby-remark-autolink-headers

同じくgatsby-config.jsには「gatsby-transformer-remark」のサブプラグインとして指定し、オプション指定なしの場合は「gatsby-remark-table-of-contents」に続けて下記のように記述します。

gatsby-config.js
plugins: [
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        `gatsby-remark-table-of-contents`,
        `gatsby-remark-autolink-headers`,
      ],
    },
  },
],

記述後に記事ページを確認してみるとそれぞれの見出しにアンカー設定が追加されており、「gatsby-remark-table-of-contents」で追加された各目次をクリックすれば該当の見出しへ移動するのを確認できます。

オプション設定

「gatsby-remark-autolink-headers」もオプションがいくつか用意されており、ここではその中から利用頻度が高そうなものを紹介します。

gatsby-config.js
plugins: [
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        resolve: `gatsby-remark-autolink-headers`,
        options: {
          icon: `<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>`,
          className: `example-anchor`,
          isIconAfterHeader: false,
          elements: [`h2`, `h3`, `h4`],
        },
      ],
    },
  },
],
  • icon
    デフォルトで対象の見出しにhoverすると左側に表示される鎖アイコンを任意のアイコンに変更でき、変更する際はSVGコードを記述します。
    また、アイコン自体が不要な場合はicon: falseを指定すると表示されなくなります。
  • className
    アイコン要素に任意のclassを追加できます。
  • isIconAfterHeader
    デフォルトでは見出しの前にアイコンが表示されるのを、isIconAfterHeader: trueで見出し後に表示するよう変更できます。
  • element
    アンカー設定を追加する対象を指定でき、上のサンプルコードの場合はh2, h3, h4にのみアンカーが設定されます。