React.jsで簡単なマークダウンエディタを作ってみよう

  • ReactJS

マークダウン便利ですよね。シンプルな記法で書けて、ビューワーで綺麗にレンダリングされて内容が見れる素敵な言語です。(厳密にはビューワーでHTMLに変換されて、それにスタイルがあたっている。)

今回は、React.jsで簡単なマークダウンエディタを作ってみようと思います。

世の中にはreact-md-editorreact-simplemde-editor(EasyMDEを利用したもの)などのNiceなライブラリもありますが、勉強も兼ねて自作してみようと思います。

リポジトリ

GitHubにあげているので、見ていただければと思います。

👉 https://github.com/nemuvski/toy-react-md

あくまでサンプルということで名前にToyと付けています。クローンしておもちゃ感覚でご自身でカスタムしてみてください。🤖

実装の前に

実装する前に、実装の内容を整理しましょう。

ざっとまとめると...

  • テキストエリアプレビューエリアをページに表示する。
  • テキストエリアに書かれた文字列(マークダウン記法のもの)をHTMLに変換する。
  • HTMLへ変換した内容をサニタイズする。(HTMLタグなどを制限する)
  • プレビューエリアに変換後のHTMLを出力して表示する。

マークダウンで書かれたものをどうやってHTMLに変換するのか。サニタイズはどうするのか。次にこれらについて説明していきます。

マークダウン → HTML

markedを利用します。お手軽にマークダウンで書かれたテキストをHTML形式のテキストへ変換できます。

公式のページにも書かれているように「変換後のHTML形式のテキストをサニタイズしてから使ってね」とあるため、併せて対応します。これについては後で説明します。

(今回の実装に限らず、基本的にユーザーに入力されたものをページ上で出力する際はサニタイズするのは必須です。)

導入するコマンドを次に示します。TypeScriptで実装する場合は型定義@types/markedも一緒にインストールします。

yarn add marked @types/marked

サニタイズ

DOMPurifyを利用します。許可する(サニタイズの際に除去しない)タグや属性を指定できます。

導入するコマンドを次に示します。TypeScriptで実装する場合は型定義@types/dompurifyも一緒にインストールします。

yarn add dompurify @types/dompurify

実装内容

ここからは https://github.com/nemuvski/toy-react-md を確認しながら、読んでいただければと思います。

変換・タグと属性の制限部分

src/libs/Sanitizer.tsにマークダウン→HTML変換とサニタイズの処理を記述しています。

コメントを添えているのでご確認いただければよいですが、この記事では要所を抜粋してとりあげます。

convertMarkdownToHTML関数今回作成する機能の中で肝の部分です。

import DOMPurify from 'dompurify';
import marked from 'marked';

export const convertMarkdownToHTML = (markdownText) => {
  // マークダウン記法のテキストをHTMLの文字列に変換.
  const markedText = marked(markdownText);

  // DOMPurifyでサニタイズする時のオプションを定義.
  const config = {
    // 許可する属性.
    ALLOWED_ATTR: [
      'href',
      'target',
      'rel',
    ],
    // 許可するタグ.
    ALLOWED_TAGS: [
      'p',
      'br',
      'ul',
      'ol',
      'li',
      'blockquote',
      'strong',
      'em',
      'a',
      'hr',
      'del',
      'pre',
      'code',
    ],
  };
  const htmlText = DOMPurify.sanitize(markedText, config);
  return { __html: htmlText };
};

処理の概要を説明します。

  1. 引数markdownTextmarkedでHTML形式のテキストに変換する。
  2. DOMPurifyの設定を記述した変数を用意する。(今回は例として許可するタグと属性を挙げています。表や画像を表示したい場合は必要に応じて許可するタグを追記してください。)
  3. サニタイズ(許可していないタグや属性を除く)
  4. dangerouslySetInnerHTMLに設定できる形式のオブジェクトを返却する。

dangerouslySetInnerHTMLについては公式のドキュメントを参照ください。📖 👀

特別に難しいことをしているわけでもなく、簡単に変換部分が実装できるのがお分かりいただけるかと思います。

補足:前はmarkedにサニタイズオプションがあったのですが、いつの間にかDOMPurifyを利用するように推奨するようになっていました。

プレビューエリア

src/components/MarkdownViewer.tsxにマークダウンからHTMLへ変換した内容を出力するコンポーネント<MarkdownViewer>を用意しました。

内容は以下のような感じです。例によって重要な部分だけ抜粋しています。

入力された内容(生のマークダウンで書かれたテキスト)をプロパティで受け取り、それをconvertMarkdownToHTML関数で変換し、出力する要素のdangerouslySetInnerHTMLに設定しています。

import React from 'react';
import {convertMarkdownToHTML} from "../libs/Sanitizer";

const MarkdownViewer = (props) => {
  return (
    <div>
      {props.markdownText === ''
        ? <p>※ 入力されるとプレビューに反映されます。</p>
        : <div dangerouslySetInnerHTML={convertMarkdownToHTML(props.markdownText)} />
      }
    </div>
  );
}

export default MarkdownViewer;

エディタ全体(テキストエリアとプレビューエリア)

src/components/App.tsxに記述しています。内容は次の通りです。

  • テキストエリアの要素の表示
  • 入力内容を<MarkdownViewer>に渡す

ここではコードは割愛します。

完成

要所のみ記事でとりあげましたが、リポジトリにはスタイルシートなども含まれています。(今回はそこがテーマではなかったので割愛しました)

立ち上げると次のキャプチャのような画面が確認できます。

早速、マークダウンを記述して変換されるか見てみましょう!

おわりに

今回は、React.jsで簡単なマークダウンエディタをmarkedDOMPurifyを用いて自作してみました。

機能は簡単なものにしていますが、興味がありましたら是非リポジトリにあるコードをカスタムしてみてください。💪

ご参考になれば幸いです。

この記事を共有

アバター

K.Utsunomiya
男・20代
主にWebフロントエンド技術と気になった音楽について投稿していきます。
最近ハマっていることは、クロスバイクで走ることとジムでの運動です。
詳しいプロフィール

© 2020–2021 コレ棚