Skip to main content

ツールバー、ライブプレビュー、および既存のテキストエリアの WYSIWYG

最終更新日:

テキストエリアを置き換えるのではなく拡張するマークダウンエディター。これにより、フォームの送信、検証、および必須フィールドが機能し続けます。 WYSIWYG およびプレーン Markdown モード、ライブ プレビュー、検索と置換、RTL サポート、ダーク モード。 Django、Laravel、Rails、Node.js、PHP、およびあらゆるスタックでスタンドアロンで動作します。

Frutjam も Tailwind も必要ありません。 スタイルがバンドルされているため、エディターはどのプロジェクトにも組み込まれます。

インストール

NPM (バンドラー: Vite、webpack、Rollup など)

bash
npm install markdown-text-editor
javascript
1
2
import MarkdownEditor from 'markdown-text-editor';
new MarkdownEditor('#markdown-editor');

TypeScript 定義はパッケージに同梱されているため、オプション、ツールバーのエントリ、変数の形状がチェックされ、追加のインストールなしでオートコンプリートされます。

CDN:ESモジュール

html
1
2
3
4
<script type="module">
  import MarkdownEditor from 'https://cdn.jsdelivr.net/npm/markdown-text-editor/+esm';
  new MarkdownEditor('#markdown-editor');
</script>

CDN: グローバル スクリプト タグ (IIFE)

インポートは必要ありません。MarkdownEditor はグローバル変数として自動的に使用可能です。

html
1
2
3
4
5
6
7
8
9
<form action="/api/save" method="POST">
  <textarea id="markdown-editor" name="content"># Hello World</textarea>
  <button type="submit">Save Content</button>
</form>

<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>
<script>
  new MarkdownEditor('#markdown-editor');
</script>

マークダウン エディターのデモ

クイックスタート

エディターをカスタマイズするには、オプション オブジェクトを渡します。すべてのオプションはオプションです。デフォルト値を使用するには、いずれかを省略します。

javascript
1
2
3
4
const editor = new MarkdownEditor('#markdown-editor', {
  placeholder: 'Write your markdown...',
  toolbar: ['heading', 'bold', 'italic', 'strikethrough', 'ul', 'ol', 'checklist', 'blockquote', 'link', 'preview'],
});

理念:「ネイティブファースト」

ほとんどのエディターは標準的な Web ワークフローを壊します。 MarkdownEditor はこれを採用しています。直接上に置いてあるので、 <textarea>、データを処理する新しい方法を学ぶ必要はありません。

  • データ バインディングは必要ありません: で動作します <form method="POST"> 箱から出して
  • 標準アクセス: 使用 document.getElementById('editor').value 通常の入力と同じように。
  • バックエンドに依存しない: 通常のフォーム フィールドと同様に、あらゆるバックエンド (Python、Node.js、PHP など) で動作します。

MarkdownEditor と EasyMDE / SimpleMDE の比較

ほとんどの JavaScript マークダウン エディター (EasyMDE、SimpleMDE、CodeMirror ベースのエディター) ** <textarea>** コピーを編集し、フォームの送信時に内容を書き戻します。これは、他の何かがその値を必要とするまで機能します。 required ブラウザがフォーカスできないフィールドは送信を完全にブロックし、 .value または FormData 送信前に読み取ると空の文字列が返され、htmx、Turbo、自動保存、および未保存変更のガードが破られます。 MarkdownEditor は異なります。 既存のテキストエリアのスタイルを設定し、入力したフィールドのままにするため、値はいつでも正しいものになります。

特徴マークダウンエディタEasyMDE / SimpleMDE
ネイティブのテキストエリアが保持される✅❌ 非表示、コピーとして編集
で動作します required フィールド✅❌ ブラウザが送信をブロックする
.value 送信する前に修正してください✅❌ フォームが送信されるまで空にしてください
と連載中 FormData、htmx、ターボ✅❌ エディター独自の API が必要
WYSIWYGハイブリッドモード✅❌
組み込みの検索と置換✅❌
RTLのサポート✅ 内蔵CodeMirror 経由 direction オプション
インライン イベント ハンドラー (CSP)✅ なしいくつかの
ダークモード/テーマ設定✅限定
バンドルのサイズ、gzip 圧縮53KB107KB(JS+CSS)

フレームワークの統合

MarkdownEditor はネイティブを保持するため、 <textarea>、追加のコードなしですべてのバックエンド フレームワークと統合されます。サーバーは、標準のフォーム フィールドから受け取る場合とまったく同じように、マークダウン コンテンツを受け取ります。 React と Vue の場合は数行かかりますが、これについてはこのセクションの最後で説明します。

ジャンゴ

追加 class テキストエリア ウィジェットに追加し、エディタを初期化します。 request.POST['content'] 追加の手順なしで動作します。

python
1
2
3
4
5
6
7
8
# forms.py
class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['content']
        widgets = {
            'content': forms.Textarea(attrs={'class': 'markdown-editor'}),
        }
javascript
1
2
new MarkdownEditor('.markdown-editor');
// request.POST['content'] contains the markdown on submit

ララベル

使用 f.text_area クラスの場合: $request->input('content') マークダウンを直接受け取ります。

html
1
2
<textarea name="content" class="markdown-editor">{{ old('content') }}</textarea>
<script>new MarkdownEditor('.markdown-editor');</script>

ルビー・オン・レール

で動作します form_with 箱から出して: params[:content] マークダウンが含まれています。ターボドライブの場合は、次を使用します。 turbo:load の代わりに DOMContentLoaded.

javascript
1
2
3
4
5
6
document.addEventListener('turbo:load', () => {
    document.querySelectorAll('.markdown-editor:not([data-mde-init])').forEach(el => {
        el.setAttribute('data-mde-init', 'true');
        new MarkdownEditor(el);
    });
});

Node.js / Express

req.body.content フォーム送信時にマークダウンを受け取ります。同期ステップやカスタム抽出はありません。

html
1
2
3
<textarea name="content" class="markdown-editor"></textarea>
<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>
<script>new MarkdownEditor('.markdown-editor');</script>

PHP

$_POST['content'] 標準のテキストエリアとまったく同じように機能します。ドロップインすれば、既存のフォーム処理を変更する必要はありません。

html
1
2
3
4
5
6
<form method="POST" action="save.php">
  <textarea name="content" class="markdown-editor"></textarea>
  <button type="submit">Save</button>
</form>
<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>
<script>new MarkdownEditor('.markdown-editor');</script>

反応する

エフェクト内にエディタを作成し、アンマウント時に破棄します。使用 defaultValue それよりも value: エディターはテキストエリアに直接書き込むため、制御されたバインディングはユーザーが入力している内容を上書きします。

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import { useEffect, useRef } from 'react';
import MarkdownEditor from 'markdown-text-editor';

function MarkdownField({ name, defaultValue = '', onChange }) {
    const ref = useRef(null);

    useEffect(() => {
        const editor = new MarkdownEditor(ref.current, { onChange });
        return () => editor.destroy();
    }, []);

    return &lt;textarea ref={ref} name={name} defaultValue={defaultValue} /&gt;;
}

戻る editor.destroy() エフェクトからは、開発中にエフェクトを 2 回実行する StrictMode もカバーされており、そうでない場合は 1 つのテキストエリアに 2 つのエディターが残ることになります。空の依存関係配列は意図的です。オプションはエディターの作成時に一度読み取られるため、エフェクトを再実行するとエフェクトが破棄され、変更のたびに再構築されます。

ヴュー

同じ考えです。初期値を一度設定します onMounted そして束縛しないでください :value、または発行されたすべてのキーストロークが v-model テキストエリアを上書きします。

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
&lt;script setup&gt;
import { ref, onMounted, onBeforeUnmount } from 'vue';
import MarkdownEditor from 'markdown-text-editor';

const el = ref(null);
const props = defineProps({ modelValue: { type: String, default: '' } });
const emit = defineEmits(['update:modelValue']);
let editor = null;

onMounted(() => {
    el.value.value = props.modelValue;
    editor = new MarkdownEditor(el.value, {
        onChange: value =&gt; emit('update:modelValue', value)
    });
});

onBeforeUnmount(() =&gt; editor?.destroy());
&lt;/script&gt;

&lt;template&gt;&lt;textarea ref="el"&gt;&lt;/textarea&gt;&lt;/template&gt;

として使用されます <MarkdownField v-model="content" />。単純な形式ではスキップできます v-model 他のフレームワークと同様に、送信時にテキストエリアから値を完全に読み取ります。

構成

エディターの動作とインターフェースを完全にカスタマイズするには、 options 物体。オプションを省略した場合は、デフォルト 値が使用されます。

オプションは、エディターの構築時に 1 回読み取られます。後で変更しても効果はありません。 destroy() 代わりに新しいエディタを作成します。

財産タイプデフォルト目的
modestring'plain'初期ビューを設定します。 WYSIWYG エクスペリエンスにはハイブリッドを使用し、生の構文にはプレーンを使用します。
placeholderstring'Write...'エディターが空の場合に表示されるテキスト。
toolbararray[...]どのツールがどのような順序で表示されるかを定義します。
footer偽| オブジェクトすべて見えるエディタの下に表示されるステータス バーを制御します。に設定します false 完全に非表示にするか、オブジェクトを渡して個々の統計を切り替えます。
themestringinheritedエディターのテーマ (ライト、ダーク、スノーベリー、ダークベリー) を明示的に設定します。省略した場合、エディタは継承します。 data-theme 最も近い祖先要素から、または <textarea> 自体。
minHeightnumber200コンテンツが短い場合にエディターが縮小する最小の高さ (ピクセル単位)。とペアになります maxHeight 自動拡張範囲を設定します。
maxHeightnumber500非全画面モードでエディターが拡大できるピクセル単位の最大高さ。コンテンツがこの高さを超えると、エディター内にスクロールバーが表示されます。エディターにはドラッグ ハンドルもあるので、ユーザーはこの制限を超えて手動でサイズを変更できます。
rendererfunctionmarkedプレビューに使用されるマークダウン パーサーを置き換えます。マークダウン文字列を受け取り、HTML 文字列を返す必要があります。
sanitizerfunctionDOMPurifyHTML サニタイザーを置き換えます。レンダリングされた HTML を受け取り、表示するには安全な HTML を返す必要があります。
onChangefunctionundefinedコンテンツの変更 (入力、ツールバーのアクション、元に戻す/やり直し、リストの継続) ごとにコールバックが発生します。現在のマークダウン文字列を唯一の引数として受け取ります。

🛠 ツールバーのカスタマイズ

ツールバーはモジュール式です。アレイを変更することで、最小限のエクスペリエンスまたはフル機能のパワー スイートを作成できます。

利用可能なツール

カテゴリツールキー
タイポグラフィheading, bold, italic, strikethrough, blockquote
リストul (bullet), ol (numbered), checklist
コードcode (列をなして)、 codeblock (柵で囲まれたブロック)
インサートhr (横罫)、 table (テーブルテンプレート)
メディアlink, image
編集undo, redo, indent, outdent
ビューpreview
テンプレート{ variables: [...] }、インラインで構成

ツールリファレンス

道具説明
headingドロップダウンを開いて見出しレベル H1 ~ H6 を選択します
bold太字のテキストの書式設定を有効にします。
italic斜体のテキストの書式設定を有効にします。
strikethroughテキストの取り消し線を許可します。
ol(順序付きリスト): テキストを番号付きリスト形式に変換します。
ul(順序なしリスト): テキストを箇条書きリストに変換します。
checklistテキストにチェックボックスを追加して、タスク、To-Do リスト、または完了ステータスの追跡に最適にします。
blockquote引用または強調されたテキストを強調表示します。
codeインライン コードの場合、選択したテキストを単一のバッククォートで囲みます。もう一度クリックするとバッククォートが削除されます。
codeblock選択したテキストを 3 つのバッククォートで囲まれたコード ブロックで囲みます。もう一度クリックするとフェンスが削除されます。
hrを挿入します --- 独自の行のカーソル位置に水平罫線を配置します。
tableスターター 2x3 マークダウン テーブル テンプレートをカーソル位置に挿入します。
imageマークダウン構文を使用して画像を挿入できます。
linkテキストにハイパーリンクを追加できます。
undo最後の変更を元に戻すには。
redo最後に元に戻した変更を再適用します。
indentインデントレベルを上げるには。
outdentインデントレベルを下げるには。
preview全画面の並べてプレビューを切り替えます。プレビュー ペインのチェックボックスはクリック可能で、マークダウン ソースが即座に更新されます。全画面表示を終了するには、Esc キーを押します。全画面表示で固定ヘッダーがエディターを覆う場合は、次を参照してください。 --mte-fullscreen-z-index.
💡 実装のヒント:
  • 並べ替え: ボタンは、配列にリストしたとおりの順序で表示されます。
  • 削除: 任意のキーを単純に省略します (例: image) 配列からその機能をユーザーに対して完全に無効にします
  • ネイティブ フォールバック: placeholder JS では、プラグインは自動的に placeholder HTML の属性 <textarea>

📊 フッター (ステータスバー)

フッターはエディターの下にあり、カーソルの 行、列、ドキュメントの文字数、およびオプションで単語数が表示され、すべてリアルタイムで更新されます。これはデフォルトで表示され、各統計を個別に切り替えることができます。

鍵タイプデフォルト説明
linebooleantrue現在の行番号を表示します。
colbooleantrue現在の列番号を表示します。
charsbooleantrue総文字数を表示します。
wordsbooleanfalse総単語数を表示します。デフォルトではオフ: に設定 true 有効にします。

使用例

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Default — line, col, and chars visible
new MarkdownEditor('#editor');

// Disable the footer entirely
new MarkdownEditor('#editor', { footer: false });

// Hide only character count
new MarkdownEditor('#editor', { footer: { chars: false } });

// Hide line and column, keep character count
new MarkdownEditor('#editor', { footer: { line: false, col: false } });

// Show only line number
new MarkdownEditor('#editor', { footer: { col: false, chars: false } });

// Enable word count alongside the defaults
new MarkdownEditor('#editor', { footer: { words: true } });

// Show word count only
new MarkdownEditor('#editor', { footer: { line: false, col: false, chars: false, words: true } });

🔀 編集モード

MarkdownEditor は、コンテンツを記述してフォーマットするための 2 つの異なる方法を提供します。従来の構文重視のビューと、視覚重視の最新のエクスペリエンスを切り替えることができます。

  • plain (デフォルト): クリーンで高性能な Markdown 環境。 **bold** または # heading)が表示されます。開発者やマークダウン純粋主義者に最適
  • hybrid: WYSIWYG にインスピレーションを得たエクスペリエンスで、基礎となる Markdown 構造を維持しながら、入力時に書式設定 (太字、斜体、見出し) をリアルタイムでレンダリングします。
javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Default initialization (Plain Mode)
new MarkdownEditor('#markdown-editor');

// Explicit Plain Mode
new MarkdownEditor('#markdown-editor', {
    mode: 'plain'
});

// Hybrid (Visual) Mode
new MarkdownEditor('#markdown-editor', {
    mode: 'hybrid'
});

ハイブリッド モードとプレーン モードのプレビュー:

ハイブリッドモード

視覚的な書式設定は、入力中にリアルタイムでレンダリングされます。

プレーンモード (デフォルト)

軽量なエクスペリエンスを実現するために、生の Markdown 構文に焦点を当てています。

🌙 テーマ

MarkdownEditor は周囲のページからテーマを自動的に継承します。構成は必要ありません。編集者が読む data-theme 初期化時に最も近い祖先から取得されるため、すぐに使用できるサイトのテーマとの同期が保たれます。

テーマの解決方法(優先順位)

  1. theme option: オプション オブジェクトで渡される明示的なオーバーライド
  2. data-theme で <textarea>: 要素に直接設定します
  3. data-theme 任意の祖先: 例: <html>, <body>、またはラッパー <div>

利用可能なテーマ

'light' (デフォルト)、 'dark', 'snowberry', 'darkberry'

オプション 1、継承元 <html> または任意の祖先 (ゼロ構成)
html
1
2
3
4
5
6
<html data-theme="dark">
  ...
  <textarea id="markdown-editor"></textarea>
  <script>
    new MarkdownEditor('#markdown-editor'); // picks up dark automatically
  </script>
オプション 2: 設定する data-theme 直接 <textarea>
html
1
2
3
4
<textarea id="markdown-editor" data-theme="dark"></textarea>
<script>
  new MarkdownEditor('#markdown-editor');
</script>
オプション 3: 明示的 theme オプション (すべてを上書きします)
javascript
1
2
3
new MarkdownEditor('#markdown-editor', {
    theme: 'dark'
});

🎨 CSS変数によるカスタムテーマ

エディターの CSS 変数をオーバーライドすることで、エディターの外観を完全にカスタマイズできます。 .markdown-editor-wrapper 要素または任意の [data-theme] セレクタ。すべての色で使用されているのは、 OKLCH色空間 知覚的に均一な結果が得られます。

変数目的ライトデフォルトダークデフォルト
--color-base編集者の背景oklch(100% 0 0)oklch(10.9% 0 0)
--color-on-base主要なテキストの色oklch(22% 0 0)oklch(98% 0 0)
--color-primaryプライマリアクセント (ツールバーがアクティブ、リンク)oklch(51.1% .262 277)oklch(66.4% .184 286)
--color-on-primary原色の表面上の文字oklch(96.2% .018 272)oklch(10% .01 270)
--color-secondary第二アクセントoklch(59.1% .293 323)oklch(65% .18 220)
--color-accent強調表示アクセント (インライン コード、斜体)oklch(54.1% .281 293)oklch(75% .18 50)
--color-neutralニュートラルなサーフェス(境界線、仕切り)oklch(15% 0 0)oklch(85% 0 0)
--color-errorエラー状態の色oklch(57.7% .245 27)oklch(60% .22 30)
--border-radiusエディターフレームの角丸め0.25rem
カスタムテーマの例

任意の変数をオーバーライドします .markdown-editor-wrapper エディターの初期化後、またはカスタム定義 [data-theme] スタイルシート内のブロック:

css
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/* Override individual variables */
.markdown-editor-wrapper {
    --color-primary: oklch(60% 0.2 30);   /* orange accent */
    --border-radius: 0.5rem;
}

/* Or define a full custom theme */
[data-theme="brand"] .markdown-editor-wrapper,
.markdown-editor-wrapper[data-theme="brand"] {
    --color-base:       oklch(15% 0.01 250);
    --color-on-base:    oklch(95% 0 0);
    --color-primary:    oklch(65% 0.22 145);   /* green */
    --color-on-primary: oklch(10% 0 0);
    --color-accent:     oklch(75% 0.18 60);
    --color-neutral:    oklch(80% 0 0);
    --border-radius:    0.75rem;
}
javascript
new MarkdownEditor('#markdown-editor', { theme: 'brand' });

🏷 変数

プレースホルダーを挿入するためのツールバー ドロップダウンを追加します。電子メール、請求書、契約書のテンプレートなど、ドキュメントの作成者がプレースホルダー構文を定義した開発者ではない場合に便利です。読みやすい名前を選択すると、正しい構文が挿入されます。

javascript
1
2
3
4
5
6
7
8
9
new MarkdownEditor('#markdown-editor', {
    toolbar: ['bold', 'italic', 'link',
        { variables: [
            { label: 'Customer Name', value: '{{customer.name}}' },
            { label: 'Invoice No',    value: '{{invoice.number}}' }
        ]},
        'preview'
    ]
});

ツールはインラインで構成されます。 toolbar 配列なので、他のボタンとの位置はあなた次第です。ボタンにはラベルがリストされ、ラベルをクリックするとそのラベルが挿入されます。 value カーソルで、選択内容を置き換えます。リストが空の場合は何も表示されません。

プレビューのサンプル値

与えられたエントリ sample は、そのサンプルをプレビューに表示しますが、テキストエリアには実際のプレースホルダーが保持されます。どちらかが含まれていないエントリは書かれたとおりに表示されるため、両方を混合することができます。

javascript
1
2
3
4
5
6
7
{ variables: [
    { label: 'Customer Name', value: '{{customer.name}}', sample: 'Hannes' },
    { label: 'Invoice No',    value: '{{invoice.number}}' }
]}

// textarea : Hi {{customer.name}}, invoice {{invoice.number}}
// preview  : Hi Hannes, invoice {{invoice.number}}

グループ化

エントリーをする items の代わりに value 見出しセクションをレンダリングします。グループ化されたエントリとフラットなエントリを 1 つのリストに混在させることができます。

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{ variables: [
    { label: 'Today', value: '{{today}}', sample: '10 September 2026' },
    { label: 'Customer', items: [
        { label: 'Name',  value: '{{customer.name}}',  sample: 'Hannes' },
        { label: 'Email', value: '{{customer.email}}', sample: 'hannes@example.com' }
    ]},
    { label: 'Invoice', items: [
        { label: 'Number', value: '{{invoice.number}}' }
    ]}
]}

知っておくべきこと

  • エディターは変数を解決しません。 エディターはテキストを挿入し、アプリケーションは後で (通常はサーバー側で) 実際の値を置き換えます。 sample プレビューの表示内容にのみ影響します。
  • ラベルはプレーン テキストとして表示されるため、ラベル内のマークアップは表示されません。
  • 不正な形式のエントリはスローされるのではなくスキップされます。使用可能なものが何も設定されていない場合、ボタンはまったく表示されません。

🖋 カスタムレンダラー

プレビューは次のようにレンダリングされます。 マークされた そして消毒した DOMPurify。どちらも交換可能です。アプリケーションがすでに別のライブラリを使用してマークダウンをレンダリングしており、プレビューを本番環境と正確に一致させたい場合に、これを使用します。

どちらのオプションも文字列を受け取って文字列を返す単純な関数であるため、どのパーサーやサニタイザーでも機能します。

javascript
1
2
3
4
5
6
7
8
9
import MarkdownIt from 'markdown-it';
import taskLists from 'markdown-it-task-lists';
import MarkdownEditor from 'markdown-text-editor';

const md = new MarkdownIt({ linkify: true, breaks: true }).use(taskLists);

new MarkdownEditor('#markdown-editor', {
    renderer: markdown => md.render(markdown)
});

DOMPurify は引き続き出力上で実行されるため、何も設定せずに XSS 保護を維持できます。

カスタム消毒剤

レンダラーが出力するものをデフォルトで削除する場合にのみ必要です。 DOMPurify は削除します <iframe> デフォルトでは、ビデオ埋め込みは明示的に許可する必要があります。 DOMPurify は、エディターにバンドルされているコピーが内部にあるため、独自のコードにインポートする必要があります。

javascript
1
2
3
4
5
6
7
8
9
import DOMPurify from 'dompurify';

new MarkdownEditor('#markdown-editor', {
    renderer:  markdown => md.render(markdown),
    sanitizer: html => DOMPurify.sanitize(html, {
        ADD_TAGS: ['iframe'],
        ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder']
    })
});

バンドラーの代わりにスクリプト タグを使用して、エディターと一緒に DOMPurify を読み込みます。

html
1
2
<script src="https://cdn.jsdelivr.net/npm/dompurify"></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script>

知っておくべきこと

  • プレビューのみ。 ハイブリッド モードのライブ フォーマットは別の内部レンダラーを使用するため、影響を受けません。
  • タスク リストにはプラグインのサポートが必要です。 クリック可能なチェックボックスは、次の検索によって見つかります。 input[type="checkbox"] 出力にはマークダウンが必要です markdown-it-task-lists。エディターは、タスク リスト構文が検出され、チェックボックスが検出されない場合、警告をログに記録します。
  • 両方とも同期である必要があります。文字列を返します。アン async 関数の書き込み [object Promise] プレビューに入ります。
  • サニタイザーを交換すると、保護が置き換えられます。 などのパススルー html => html サニタイズを完全に無効にし、完全に信頼できるコンテンツに対してのみ安全です。

🎨 内部要素のスタイル設定

CSS 変数は継承するため、ほとんどのテーマをカバーするため、CSS 変数をオンに設定すると、 .markdown-editor-wrapper ツールバー、ボタン、プレビュー、フッターに到達します。必要なものを公開する変数がない場合にのみ、クラス名に手を伸ばしてください。

css
1
2
3
4
5
/* Variables set on the wrapper inherit down to every child */
.markdown-editor-wrapper {
    --border-radius: 12px;   /* rounds the editor and its toolbar buttons */
    --color-primary: oklch(60% 0.2 30);
}

クラスリファレンス

これらのクラス名は安定しており、安全にスタイル設定できます。

クラス要素
.markdown-editor-wrapperエディタ全体を包む外側のコンテナ
.toolbar編集領域の上のツールバー ストリップ
.markdown-btn個別のツールバーボタン
.preview-btnプレビュー/全画面切り替えボタン
.editor-layout編集領域とプレビューを並べて保持するグリッド
.textarea-wrapper編集領域の周囲のラッパー
.editor-textarea基礎となる textarea 要素
.display-layerレンダリングされた書式設定レイヤー、ハイブリッド モードのみ
.preview-wrapperプレビュー列
.preview-contentプレビュー内のレンダリングされたマークダウン
.editor-footerエディターの下のステータスバー
.find-replace-panelパネルを見つけて交換する
css
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* Some variables are set by the component on itself, which beats an
   inherited value. Target the element directly for those. */
.markdown-editor-wrapper .markdown-btn {
    --btn--font-size: 0.875rem;
}

/* And use classes for anything no variable exposes */
.markdown-editor-wrapper .toolbar {
    border-bottom: 2px solid oklch(60% 0.2 30);
}

1人の編集者をターゲットにする

1 ページに複数のエディタがある場合、そのうちの 1 つを次のようにターゲットにします。 data-editor。ラッパーはその ID をミラーリングします。 <textarea>、 それで <textarea id="notes"> あなたに与えます [data-editor="notes"]。 ID 自体はテキストエリアに残るため、 getElementById 働き続けます。

css
1
2
3
4
/* one editor only */
[data-editor="notes"] {
    --border-radius: 0;
}

🪟 フルスクリーンとレイヤー化 (z-index)

全画面表示でエディターが使用するのは z-index: 10000、ほとんどの UI フレームワークが固定ヘッダーとオーバーレイ用に予約しているレイヤーをクリアします。固定ヘッダーまたはサイドバーが依然としてエディターを覆っている場合は、この値を上げます。

でオーバーライドします --mte-fullscreen-z-index。この値はフルスクリーンでのみ適用され、継承されるため、任意の祖先に設定すると、その下のすべてのエディタがカバーされます。

css
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/* every editor on the page */
.markdown-editor-wrapper {
    --mte-fullscreen-z-index: 20000;
}

/* one section only - the value inherits down */
#admin-panel {
    --mte-fullscreen-z-index: 20000;
}

/* a single editor, by its textarea id */
[data-editor="notes"] {
    --mte-fullscreen-z-index: 20000;
}

コンテンツAPI

MarkdownEditor の中核的な強みの 1 つは、基礎となる要素を保持していることです。 <textarea> 完全に同期しています。最新の JavaScript フレームワークを使用している場合でも、Django、PHP、Laravel などの従来のバックエンドを使用している場合でも、ワークフローはシンプルかつネイティブのままです。

コンテンツの読み取りと書き込み

1\。ネイティブの方法 (推奨)

エディターは標準のテキストエリアを拡張するため、使い慣れた DOM メソッドを使用できます。これは、新しい API を学習せずにデータを操作する最も速い方法です。

javascript
1
2
3
4
5
// Retrieve content via ID
const markdown = document.getElementById('markdown-editor').value;

// Set content via ID (The editor UI updates automatically)
document.getElementById('markdown-editor').value = "# New Heading Content";

2\。変数参照の使用

textarea 要素への参照がある場合は、それを直接使用できます。ライブラリ固有の API は必要ありません。

javascript
1
2
3
4
5
6
7
const textarea = document.getElementById('markdown-editor');

// Retrieve content
const markdown = textarea.value;

// Set content (the editor UI reflects this immediately)
textarea.value = "## Updated via JS";

3\。サーバー側の初期コンテンツの設定

初期コンテンツを直接設定する推奨方法は、 <textarea> HTML: これはあらゆるバックエンド フレームワーク (Django、Laravel、Rails、PHP など) で自然に動作し、エディターが init 時に自動的にレンダリングします。

html
1
2
<!-- Recommended: set content server-side -->
<textarea id="markdown-editor"># Hello World</textarea>

実行時にコンテンツを読み取りまたは更新するには、ネイティブの textarea 価値。電話 editor.render() 更新後にプレビューとハイブリッド レイヤーを更新します。

javascript
1
2
3
4
5
6
7
8
const textarea = document.getElementById('markdown-editor');

// Read
const markdown = textarea.value;

// Update at runtime
textarea.value = '# New content';
editor.render();

4\。エディターを破棄します。 destroy()

電話 editor.destroy() エディターの DOM ラッパーを削除し、元の DOM ラッパーを復元します。 <textarea> ドキュメント内の位置に移動します。単一ページのアプリケーションでビューをアンマウントするときに便利です。

javascript
1
2
3
4
const editor = new MarkdownEditor('#markdown-editor');

// Remove the editor and restore the plain textarea
editor.destroy();

変化に対応する onChange

渡す onChange コンテンツが変更されるたびに通知を受けるコールバック。現在のマークダウン文字列を受け取ります。

javascript
1
2
3
4
5
const editor = new MarkdownEditor('#markdown-editor', {
    onChange(value) {
        console.log('Content changed:', value.length, 'characters');
    }
});

ドラフトの自動保存 localStorage

使用 onChange キーストロークごとに下書きを保存します。エディタを初期化する前にテキストエリアを事前に入力して復元します。

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const DRAFT_KEY = 'my-page-draft';

// Restore saved draft before init (only if textarea starts empty)
const textarea = document.getElementById('markdown-editor');
const saved = localStorage.getItem(DRAFT_KEY);
if (saved && !textarea.value) textarea.value = saved;

// Save on every change
const editor = new MarkdownEditor('#markdown-editor', {
    onChange(value) {
        localStorage.setItem(DRAFT_KEY, value);
    }
});

// Clear draft after successful form submission
document.querySelector('form').addEventListener('submit', () => {
    localStorage.removeItem(DRAFT_KEY);
});

フォームの送信

MarkdownEditor はネイティブ上に直接構築されているため、 <textarea>、すぐに使用できるすべてのバックエンド フレームワーク (Django、Laravel、PHP、Ruby on Rails など) と互換性があります。

ここで「ネイティブファースト」の哲学が光ります。フォームを送信する前にデータを手動で同期する必要はありません。ブラウザはエディタを標準の入力フィールドとまったく同じように扱います。

html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<form method="POST" action="/api/submit">
  <textarea id="markdown-editor" name="content" class="h-48" rows="5">
    # Initial Content
  </textarea>

  <button type="submit">Submit to Server</button>
</form>

<script>
  // Just initialize it. That's it.
  new MarkdownEditor('#markdown-editor');
</script>

注記: MarkdownEditorプラグインの初期化が必須

標準の HTML を使用するだけです <form>。の name textarea の属性は、サーバーがコンテンツを識別するために使用するものです。

🚀 バックエンドにとって大きな変革となる理由

エディターはネイティブを保持するため、 <textarea> この動作では、サーバーはデータを標準文字列として処理します。追加のロジックは必要ありません: いいえ preventDefault() そしてマニュアルなし FormData 工事。

💡 これが「キラー機能」である理由:

ほとんどのエディター (Quill、Editor.js、simpleMDE、easyMDE など) は、データを複雑な JSON 構造で保存します。開発者がこれらを使用する場合、データベース スキーマとレンダリング ロジックを書き直す必要があります。

MarkdownEditor を使用すると、開発者は古い Web サイトを取得して、プレーンな Web サイトを置き換えることができます。 <textarea> エディターで編集すると、バックエンドはそれが変更されたことさえ認識しません。いつもと同じ生のテキストを受け取るだけですが、ユーザーは 10 倍優れたエクスペリエンスを得ることができます。

フレームワーク/言語Markdown コンテンツにアクセスする方法
PHP$_POST['content']
ジャンゴrequest.POST.get('content')
Node.js (高速)req.body.content
ララベル$request->input('content')
ルビー・オン・レールparams[:content]

🖼️ 高度な画像アップロード

画像のアップロードをネイティブに処理することは、遅くてメモリを大量に消費する Base64 文字列に依存するのではなく、パフォーマンスと SEO の両方において大きなメリットとなります。

構成オプション

画像ツールは、 fileInput サーバーへの直接アップロードを処理するための構成。

  • accept: 許可される画像形式の配列を定義します (例: 「webp」、「avif」)
  • uploadUrl: バックエンド エンドポイントを指定します。 File オブジェクトは経由で送信されます POST
  • params: 画像ファイルと一緒に追加データ (CSRF トークン、ユーザー ID、フォルダー名など) を送信するためのオプションのオブジェクト

使用例(フルコンフィグ)

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const options = {
  placeholder: 'Start writing...',
  toolbar: [
    'link',
    {
      image: {
        fileInput: {
            accept: ['webp', 'avif'], // restrict the image upload format
            uploadUrl: '/api/upload', // Your upload endpoint
            params: {
                _token: 'your_csrf_token_here', // Essential for Laravel/Django
                folder: 'blog_posts'
            }
        },
        // Supports boolean: true/false OR object: { required: true }
        altInput: { required: true }
      }
    },
    'preview'
  ],
}
const editor = new MarkdownEditor('#markdown-editor', options);

📡 サーバー統合

リクエスト

編集者が送信するのは、 POST としてリクエストする multipart/form-data。デフォルトでは、次のものが含まれます。

  • image_file: 実際のファイルオブジェクト
  • image_alt: ユーザーが入力した代替テキスト
  • ...さらに、 params 物体

必要な対応

アップロードが成功したことを確認し、画像をエディタに挿入するには、サーバーは次の JSON 構造を返す必要があります**。

json
1
2
3
4
{
  "success": true,
  "image_path": "https://cdn.yourdomain.com/uploads/image.webp"
}

注意: 必ずキーを使用してください image_path アップロードされた画像の URL です。

画像代替テキストの検証 (altInput)

コンテンツがアクセス可能で SEO フレンドリーであることを保証するために、MarkdownEditor はデフォルトで代替テキストの検証を強制します。

  • デフォルトの動作: altInput は定義されていません。デフォルトでは { required: true }
  • アクセシビリティの強制: 代替説明が提供されるまで、ユーザーは画像を挿入できません。

1\。デフォルト (設定は必要ありません)

javascript
1
2
3
4
// Alt text is REQUIRED by default
image: {
  fileInput: { uploadUrl: '/api/upload' }
}

2\。短縮表現 (検証を無効にする)

説明のない画像を許可したい場合は、ブール値を次のように設定します。 false.

javascript
1
2
3
image: {
  altInput: false // Users can now skip the alt text field
}

3\。オブジェクトベース (明示的)

javascript
1
2
3
4
5
image: {
    altInput: {
        required: false // Disables alt text validation — users can skip the alt field
    }
}

標準的な画像の使用 (いいえ fileInput)

もし fileInput が構成されていない場合、エディターはデフォルトで単純な URL ベースのモーダルになります。これは、ユーザーが主に外部イメージ ホストにリンクしている場合に最適です。

javascript
1
2
3
4
5
6
7
8
const options = {
  toolbar: [
    'link',
    'image',
    'preview'
  ],
}
const editor = new MarkdownEditor('#markdown-editor', options);

💡 params を使用する理由?

Laravel や Django などのフレームワークでは、CSRF トークンがないとファイルをアップロードできません。追加することで _token に params オブジェクトを使用すると、リクエストはバックエンドのセキュリティ ミドルウェアをシームレスに通過し、サーバー側コントローラーの「ゼロ ロジック」哲学が維持されます。

⌨️ キーボード ショートカット

一般的な書式設定アクションは、ツールバーに触れずにキーボードから直接トリガーできます。各ショートカットは、対応するツールバー ボタンのツールチップにも表示されます。

ショートカットアクション
Ctrl + B  /  ⌘ B太字を切り替えます
Ctrl + I  /  ⌘ Iトグル 斜体
Ctrl + K  /  ⌘ Kリンクの挿入
Ctrl + `  /  ⌘ `インラインの切り替え Code
Ctrl + Shift + S  /  ⌘ ⇧ S取り消し線の切り替え
Ctrl + 1  /  ⌘ 1見出し1
Ctrl + 2  /  ⌘ 2見出し2
Ctrl + 3  /  ⌘ 3見出し 3
Ctrl + L  /  ⌘ L箇条書きリストの切り替え
Ctrl + Z  /  ⌘ Z元に戻す
Ctrl + Shift + Z  /  ⌘ ⇧ Zやり直し
Tab選択した行をインデントします
Shift + Tab選択した行のインデントを解除する
Ctrl + F  /  ⌘ F検索パネルを開く
Ctrl + H  /  ⌘ H検索と置換パネルを開く
Ctrl + Shift + F  /  ⌘ ⇧ F全画面プレビューの切り替え
F11全画面プレビューの切り替え
Escape検索パネルを閉じる / 全画面プレビューを終了する

🔍 検索と置換

組み込みの検索および置換パネルはエディタ内で使用できます。ブラウザ拡張機能や別個のツールは必要ありません。

  • プレス Ctrl + F (または ⌘ F) 検索パネルを開きます
  • プレス Ctrl + H (または ⌘ H) [検索と置換] パネルを開きます
  • 検索では 大文字と小文字が区別されません。ライブ マッチ カウンター (例: 3/12) が表示されます。
  • ▲ / ▼ ボタンまたは Enter / Shift + Enter
  • 置換 は、現在強調表示されている一致を置換します。 すべて置換 すべての出現箇所を一度に置換します
  • プレス Escape パネルを閉じてエディタにフォーカスを戻すには

パネルはエディターのコンテンツ領域の右上隅にフロートしており、書き込みを中断しません。

特徴

🔌 ネイティブフォームの統合

標準とまったく同じように動作します <textarea>。複雑な API は必要ありません。 value または name 属性。これは、PHP、Django、または Node.js での標準の HTML フォーム送信で「機能」します。

🖼️ 高度な画像アップロード

API 経由でネイティブ サーバーのアップロードを構成します。独自の CDN で画像をホストすることで、ページの読み込みを高速化し、優れた SEO を実現するには、重い Base64 文字列を避けてください。

🔀 ハイブリッドモードとプレーンモード

を切り替えます ハイブリッド (WYSIWYG) ビジュアル編集の経験または プレーンマークダウン 従来のコーディング感覚のモード。

🚀 高性能

あ 53 KB gzip圧縮 「重いコンテンツ」向けに最適化されたバンドル (252 KB 縮小、CSS が含まれています)。入力遅延やパフォーマンスの低下を引き起こすことなく、大量のドキュメントや大きなファイルを処理できます。デバウンスされたプレビュー更新、キャッシュされたスタイル計算、競合のないキーボード処理: したがって、Tab と Enter は常に 1 つのことを実行します。

🌍 組み込みの RTL サポート

アラビア語、ウルドゥー語、ペルシア語などの右から左に記述する言語のネイティブ サポート。グローバルにアクセス可能なアプリケーションの構築に最適です。

✨ 構文の強調表示

明確なコードとマークダウン形式により可読性が向上しました。

🌙 アダプティブテーマ

自動ダークモードのサポートが含まれます。システム設定または フルジャムUI シームレスな視覚体験のためのライブラリ。

📝 スマート編集

順序付きリスト、順序なしリスト、チェックリストの GitHub スタイルの自動リスト継続: press Enter そして編集者はパターンを続けます。プレビュー ペインのチェックボックスはクリック可能で、マークダウン ソースに即座に同期されます。

📱 完全にレスポンシブ

デスクトップ、タブレット、スマートフォンに完璧に適応する流動的なモバイルファースト UI により、外出先での編集が可能です。

📦 ユニバーサルサポート

と互換性があります ESM、UMD、CommonJS、IIFE。 CDN 経由ですぐに動作します (<script src>)、npm、または任意のバンドラー (Vite、webpack、Rollup): 追加の構成は必要ありません。

♿ デフォルトでアクセス可能

完全な ARIA サポートの組み込み: ツールバーのランドマーク、ラベル付きプレビュー領域、スクリーンリーダーに優しいボタン、 aria-pressed プレビュートグルで、 disabled そして aria-disabled 非アクティブなツールで、モーダルが閉じたときにフォーカスが正しく復元されます。

🛡️ CSS 競合なし

エディターのスタイルは以下に完全に適用されます。 .markdown-editor-wrapper。 Tailwind のグローバル プリフライトは除外されているため、エディターは Bootstrap、Tailwind、またはその他のフレームワークと安全に共存でき、それらのスタイルを損なうことはありません。

⌨️ キーボード ショートカット

Ctrl+B, Ctrl+I, Ctrl+K, Ctrl+`, Ctrl+Shift+S: マウスに触れずに行う一般的な書式設定アクション。各ショートカットは、ツールバー ボタンのツールチップに表示されます。

🔍 検索と置換

プレス Ctrl+F 見つけるか、 Ctrl+H をクリックして検索と置換を開きます。エディターを離れることなく、ライブ一致カウンター、次/前のナビゲーション、単一置換、およびすべて置換による大文字と小文字を区別しない検索。

🔒 XSS セーフプレビュー

レンダリングされたプレビューは次のようにサニタイズされます。 DOMPurify DOM に書き込まれる前に。細工されたマークダウン入力内のスクリプト タグ、インライン イベント ハンドラー、悪意のある URL は自動的に削除されます。構成は必要ありません。

▶️ リアルタイムプレビュー

入力するとすぐにマークダウンがレンダリングされるのを確認してください。

🔗 簡単な統合

最小限のセットアップであらゆる Web プロジェクトにシームレスに統合できます。

🛠️ カスタマイズ可能なツールバー

太字、斜体などのツールバー オプションを動的に構成および並べ替えます。

完全な構成例

この包括的な例を使用して、カスタム ツールバーの順序付けや高度な画像アップロード処理など、すべての主要な機能を備えた MarkdownEditor を初期化します。

javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const editor = new MarkdownEditor('#markdown-editor', {
    mode: 'hybrid',
    placeholder: 'Start writing...',
    footer: {
        line: true,
        col: true,
        chars: true,
        words: true,
    },
    onChange(value) {
        console.log('Content updated:', value.length, 'characters');
    },
    toolbar: [
        'heading', 'bold', 'italic', 'strikethrough', 'blockquote',
        'ul', 'ol', 'checklist',
        'code', 'codeblock', 'hr', 'table',
        {
            image: {
                fileInput: {
                    accept: ['webp', 'avif', 'png'],
                    uploadUrl: '/api/upload'
                }
            }
        },
        'link', 'undo', 'redo', 'indent', 'outdent', 'preview'
    ],
});

// Read content natively
const markdown = document.getElementById('markdown-editor').value;

// destroy() when the view unmounts (SPAs)
// editor.destroy();

これは役に立ちましたか?

GitHub スターは、他の開発者がエディターを発見するのに役立ちます。の一部です フルートジャム。そこにあるスターも役に立ちます。

GitHub でスターを付ける