18
13

More than 3 years have passed since last update.

react-markdownに目次をつける

Last updated at Posted at 2021-06-22

はじめに

react-markdownの目次の作り方を紹介します。
(もっといい方法あるかもです。。)

ソースコード

スタイリング0です
目次を押すと、該当の箇所に移動するだけのものを作ります。

完成品

index.js
import ReactMarkdown from "react-markdown";

const body = `
## タイトル1
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
## タイトル2
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
## タイトル3
#### こんばんは
#### こんばんは 
#### こんばんは
#### こんばんは 
#### こんばんは 
#### こんばんは`

export default function Home() {
  const H2 = ({ node, ...props }) => {
    return (
        <h2 id={node.position?.start.line.toString()}>{props.children}</h2>
    );
  }

  const ankerLink = ({ node, ...props }) => {
    return (
        <a href={"#"+node.position?.start.line.toString()}>{props.children}</a>
    );
  }

  return (
    <div>

      {/* 目次 */}
      <ReactMarkdown
      allowedElements={["h2"]}
      components={{
          h2: ankerLink,
        }}>
          {body}
      </ReactMarkdown>

      {/* 本文 */}
      <ReactMarkdown
        components={{
          h2: H2,
        }}
      >
          {body}
      </ReactMarkdown>

    </div>
  )
}

手順では↑を順番に書いていくだけです。

手順

ライブラリのインストール

yarn add react-markdown

マークダウンで書いたものを表示させる

index.js
import ReactMarkdown from "react-markdown";

const body = `
## タイトル1
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
* おはよう。
## タイトル2
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
1. こんにちは。
2. こんにちは。
3. こんにちは。
## タイトル3
#### こんばんは
#### こんばんは 
#### こんばんは
#### こんばんは 
#### こんばんは 
#### こんばんは`

export default function Home() {
  return (
    <div>
      <ReactMarkdown>
          {body}
        </ReactMarkdown>
    </div>
  )
}

bodyがマークダウンで書いた内容ですね
ReactMarkdownのchildrenにbodyを渡します。

こうやって書くこともできます

ㅤ.js
<ReactMarkdown
  children={body}
/>

これでマークダウンで書かれたものをhtmlとして表示することができます。

見出しにidを与える

index.js

export default function Home() {
  const H2 = ({ node, ...props }) => {
    return (
        <h2 id={node.position?.start.line.toString()}>{props.children}</h2>
    );
  }
  return (
    <div>
      <ReactMarkdown
        components={{
          h2: H2,
        }}
      >
          {body}
        </ReactMarkdown>
    </div>
  )
}

componentsオプションを使うことで、要素を編集できます。
マークダウンのh2を自分で作ったh2にしています。
左に要素の指定、右に自分で作ったものを指定します。
今回はh2だけですが、h2とh3など複数指定できます。

nodeやporpsにどんな値が入っているかはconsole.logなどで確認してみてください。

見出しだけを表示させる

index.js

<ReactMarkdown allowedElements={["h2"]}>
    {body}
</ReactMarkdown>

これでh2のみが表示されます。

index.js
<ReactMarkdown allowedElements={["h2"]}>
  {body}
</ReactMarkdown>

<ReactMarkdown
   components={{
     h2: H2,
   }}
>
  {body}
</ReactMarkdown>

目次ようと本文用で2つ作ります。

見出しから飛べるようにする

index.js
const ankerLink = ({ node, ...props }) => {
    return (
        <a href={"#"+node.position?.start.line.toString()}>{props.children}</a>
    );
}
index.js
<ReactMarkdown
  allowedElements={["h2"]}
  components={{
     h2: ankerLink,
  }}>
  {body}
</ReactMarkdown>

見出しだけを表示している方のh2を編集します。
見出しにidを与えると同じようにh2を編集します

同じマークダウンを使っているので、idが同じになります。

これで目次をクリックすることで、見出しに飛ぶことができるようになりました。

あとは、自由にスタイリングしていってください。

おまけ

このままだと、headerなどがある時に被ってしまいます。
H2に、「paddidng-top: 20px;」、「margin-top: -20px;」などを持たせることでいい感じに表示できます。

Tailwind使って少しだけスタイリングしました

参考文献

18
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
13