
【react-markdown】コードブロックを追加してハイライトする
2022-04-25
2022-04-25
はじめに
昨日たべた柿のドライフルーツ、おいしかった、こふです。
本記事では react-markdown
を使って任意のプログラミング言語を書ける場所と、ハイライト(色付け)を行います。
環境
React
を使います。必要な npm
ライブラリは適宜インストールしてください。
インストール後の Warning が出る方は以下の記事を参考に修正してください。
更新予定:npm install 時のエラーの解決方法 3 ステップ
terminal
1❯ node -v 2v16.14.0
package.json
1... 2"dependencies": { 3 ... 4 "react": "^17.0.2", 5 "react-dom": "^17.0.2", 6 "react-markdown": "^8.0.1", 7 "react-syntax-highlighter": "^15.5.0", 8 ... 9 }, 10 "devDependencies": { 11 ... 12 "autoprefixer": "^10.4.0", 13 "eslint": "^8.13.0", 14 "postcss": "^8.4.5", 15 "remark-parse": "^10.0.1", 16 "tailwindcss": "^3.0.7", 17 "typescript": "4.5.4" 18 ... 19 } 20...
ソースコード
1<ReactMarkdown 2 className="省略" 3 children={markdown} 4 components={articleComponents} 5/>
1import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' 2import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' 3import { CodeComponent } from 'react-markdown/lib/ast-to-react' 4 5const customCode: CodeComponent = ({ inline, className, children }) => { 6 const style = atomDark 7 const match = /language-(\w+)(:?.+)?/.exec(className || '') 8 const lang = match && match[1] ? match[1] : '' 9 const name = match && match[2] ? match[2].slice(1) : '' 10 if (lang === 'link') { 11 // blog card 12 } else if (lang === 'twitter') { 13 // twitter embed 14 } 15 return !inline && match ? ( 16 <> 17 {name && ( 18 <span className="rounded-md bg-stone-200 py-1 px-2 text-sm dark:bg-stone-600"> 19 {name} 20 </span> 21 )} 22 <SyntaxHighlighter 23 children={String(children).replace(/\n$/, '')} 24 style={style} 25 language={lang} 26 PreTag="div" 27 className="border-2 text-base dark:border-stone-400 md:text-lg" 28 /> 29 </> 30 ) : ( 31 <code className="mx-1 rounded-md bg-stone-200 py-1 px-2 text-red-600 dark:bg-stone-600 dark:text-red-300"> 32 {children} 33 </code> 34 ) 35} 36export const articleComponents = { 37 code: customCode, 38}
ソースコード解説
分割し、説明を加えます。
ArticleContainer.tsx
1<ReactMarkdown 2 className="" 3 children={markdown} 4 components={articleComponents} 5/>
これは react-mardown
のコンポーネントを使い、Props
に string
型の markdown
とカスタムしたコンポーネントを渡します。
ArticleComponents.tsx
1import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' 2import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism' 3import { CodeComponent } from 'react-markdown/lib/ast-to-react' 4 5const customCode: CodeComponent = ({ inline, className, children }) => { 6 const style = atomDark 7 const match = /language-(\w+)(:?.+)?/.exec(className || '') 8 const lang = match && match[1] ? match[1] : '' 9 const name = match && match[2] ? match[2].slice(1) : '' 10 if (lang === 'link') { 11 // blog card 12 } else if (lang === 'twitter') { 13 // twitter embed 14 }
ハイライトで囲う Prism
、コードのカラーを入れてくれるテーマから atomDark
、そして react-markdown
から CodeComponent
型をインポートします。
正規表現の説明と方針に関しては以下で解説しています。
https://blog.cohu.dev/react-markdown-blog-card#どうやるか
話はそれますが、言語(lang)ごとに出し分けていて、ブログカード・Twitter 埋め込みをしている形です。
style
変数にテーマ情報を代入します。もしダークモードでは明るい色にしたいのであれば、三項演算子などを使って代入を分けてください。
余談ですが、このサイトでは投稿日時点でハイライトのテーマは一種類に限定しています。
理由は、デフォルトの CSS 値の上書きが面倒だからです。
テーマの種類によって初期の CSS にフォントサイズが与えられているものがあります。
その場合、Tailwind CSS を使っているのですが上書きができません。
インラインの CSS を核などで対処は可能ですし、他の CSS ファイルから読み込むことも、styled-jsx を使うことも可能です。
しかし、あまり明るい色にする価値を感じていないので、一種類で大丈夫という判断です。
今後 react-markdown
から軽いライブラリに変更予定なので、仮置きみたいなものです。
1... 2 return !inline && match ? ( 3 <> 4 {name && ( 5 <span className="rounded-md bg-stone-200 py-1 px-2 text-sm dark:bg-stone-600"> 6 {name} 7 </span> 8 )}
ここで以下のパーツを作っています。ファイルの名前を見せることで伝わりやすくする目的です。

1 <SyntaxHighlighter 2 children={String(children).replace(/\n$/, '')} 3 style={style} 4 language={lang} 5 PreTag="div" 6 className="border-2 text-base dark:border-stone-400 md:text-lg" 7 /> 8</> 9) : (
ここがコード本体の場所で、子要素にマークダウンを渡します。
マークダウンはパースすると改行が入るので、replace
で取り除いています。
replace
のドキュメント:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace
style
にテーマを、language
にプログラミング言語を入れます。
1 <code className="mx-1 rounded-md bg-stone-200 py-1 px-2 text-red-600 dark:bg-stone-600 dark:text-red-300"> 2 {children} 3 </code> 4 ) 5} 6export const articleComponents = { 7 code: customCode, 8}
以下のような inline
のコードのデザインです。特にこだわりはありません。

他のやり方
数多くのライブラリがあるので、やり方は無限大です。
しかし、ハイライトは Prism.js
というのが一般的に普及しており、使っておけば問題ないといえます。
markdown
をパースするライブラリはラップしている react-markdown
が楽でおすすめです。
が、かゆいところに手が届かないので書き換え予定です。後日、記事にします。
おわりに
最後まで読んでいただきありがとうございました。
これでコードを綺麗に見せることができます、どんどん書いたコードを貼り付けよう!