【実務・中級編】contenteditable属性とインライン要素 – HTML実践ガイド

`contenteditable`でインライン要素を扱う際、僕たちが必ず直面する「制御不能な闇」の話

現場で「このテキスト、クリックしたら直接編集できるようにして」という要件を受けたとき、真っ先に頭をよぎるのが `contenteditable` 属性ですよね。一見すると最強の魔法に見えますが、ことインライン要素を対象にすると、その「闇」は一気に深まります。

今日は、中級エンジニアの皆さんがハマりやすい「ブラウザごとの解釈の揺らぎ」と「避けては通れないDOM崩壊のリスク」について、実務の視点から切り込んでいこうと思います。

—

1. なぜインライン要素の `contenteditable` は「諸刃の剣」なのか

まず前提として、ブラウザは `contenteditable` が付与された要素内の編集において、DOMの構造を維持しようと必死に頑張ります。しかし、その「頑張り方」がブラウザによって全く異なるのが最大の苦痛です。

例えば、`` や `` の中で改行(Enterキー)を入れたとき:

  • Chrome (Blink系): 賢く `
    ` を生成してラップしようとする。
  • Firefox (Gecko系): `
    ` を挿入してインライン構造を維持しようとする。
  • Safari (WebKit系): 時折謎の `

    ` や `` が連鎖的に生成されることがある。

このように、DOMのツリー構造がユーザーのキー入力一つで激しく変動します。特に `` や `` などの意味論的なタグに `contenteditable` を直当てすると、編集過程でタグが勝手に閉じられたり、入れ子になったりして、サーバーに送信するデータが「タグの残骸」と化すのはよくある光景です。

—

2. 実務で遭遇する「DOM汚染」というセキュリティリスク

皆さんが一番恐れるべきは、XSS(クロスサイトスクリプティング)です。
`contenteditable` 領域から得られる値は、基本的に `innerHTML` で取得しますよね? ここにユーザーが `` のような文字列を貼り付けた場合、サニタイズなしでデータベースに保存すれば、それはそのままサイトの脆弱性に直結します。

「`contenteditable` は、入力内容を100%信頼してはいけない」

これが、シニアエンジニアが新人に叩き込む最初の鉄則です。

—

3. 現場で使える!安全・確実な実装パターン

では、どうすればいいのか。結論から言うと、「入力の制限」と「DOM操作の最小化」を両立させることです。以下のサンプルは、インラインでの編集を許可しつつ、改行を禁止して構造崩壊を防ぐ、最も手堅いアプローチです。

/

  • インライン要素の編集を制御する実用的なユーティリティ
  • 1. 改行入力を無効化(DOM崩壊を防ぐ)
  • 2. 貼り付け時に書式を削除(プレーンテキスト化)

/
const editableElement = document.querySelector(‘.js-inline-edit’);

editableElement.addEventListener(‘keydown’, (e) => {
// Enterキー入力を検知して改行を阻止
if (e.key === ‘Enter’) {
e.preventDefault();
editableElement.blur(); // 編集終了としてフォーカスを外す
}
});

editableElement.addEventListener(‘paste’, (e) => {
// 貼り付け時の余計なスタイルやタグを完全に排除
e.preventDefault();
const text = e.clipboardData.getData(‘text/plain’);
document.execCommand(‘insertText’, false, text);
});

ポイント解説

  • `e.preventDefault()`: これを怠ると、インライン要素の中に `
    ` や `

    ` が入り込み、レイアウトが崩壊します。

  • `insertText`: ブラウザのネイティブな貼り付け機能に頼らず、テキストとして強制挿入することで、悪意あるHTMLタグを無力化します。

—

4. プロとしてのアドバイス:`contenteditable` とどう付き合うか

正直に言えば、複雑なリッチテキストエディタを作るなら、`contenteditable` を素で扱うのはやめましょう。`ProseMirror` や `Slate.js` といった、DOMの差分を抽象化して正しく管理してくれるライブラリを使うのが、今のフロントエンド開発の「標準解」です。

しかし、今回のように「名前の変更」や「ちょっとした注釈の修正」程度のインライン編集であれば、先ほどのコードのように「入力後のDOMをクリーンにする」という意識があれば十分戦えます。

まとめ:次に実装する際、自分に問いかけてほしいこと

1. 「その要素は、本当にインライン要素である必要があるか?」(ブロック要素の方が管理はずっと楽です)
2. 「改行は必要か?」(不要なら迷わず `keydown` で止める)
3. 「値のサニタイズはサーバーサイドだけでなく、フロントでも行っているか?」

ブラウザの挙動を信じず、常に「DOMは壊れるもの」という前提でコードを書く。これが、泥臭いけれど一番頼りになるフロントエンドの流儀です。

何か不明点があれば、またいつでも聞いてください。次はもっと深い、MutationObserverを使ったDOM監視の世界についてお話ししましょうか。

コメント

タイトルとURLをコピーしました