HTMLのcontenteditable属性って一体どういう時に使うの?

2024/09/27

HTML Javascript

t f B! P L
eyecatch HTML5になって、タグの属性も機能追加されたのに、まだまだ知らない属性が存在しています。 先日、とあるサイトで、contenteditableという属性を見かけて、調べてみたらなかなかトリッキーな属性だったので、備忘録しておきます。

contenteditable属性について

通常、Webページで入力をする場合は、inputタグかtextareaタグで閲覧者の文字入力を行います。 ログインページのIDやパスワード、お問い合わせページの内容入力などは、おそらくすべてinputタグかtextareaタグでformタグ内に構成されていると思います。 これを、他のどんなタグでも、中(innerHTML)に書かれている文字列を自由に編集(書き換え)できるようにするのが、contenteditable属性です。 以下のデモで、それぞれの挙動を確認してみてください。

デモ

DIVタグ

デモのソースコード

<input type="text" value="inputタグ" style="border:1px solid black;padding:10px;width:100%;"> <textarea style="border:1px solid black;padding:10px;width:100%;min-height:80px;">textareaタグ</textarea> <div contenteditable="true" style="border:1px solid black;padding:10px;">DIVタグ</div>

contenteditableのメリット

inputとtextaareaは、contenteditableと同じと思う人も多いかもしれませんが、最も違う点で、利点でもある、ネストタグを内包できるという点です。 何なら、画像や、別ページのDOM構造もそのまま貼り付けることができるのが、contenteditable属性です。 もちろん、inputとtextareaは、いわゆる文字列だけしか扱えないので、装飾も含めたDOM構造が手軽に扱えるのが、contenteditable属性のメリットですね。

contenteditableのデメリット

いろいろなサイトでcontenteditableについて書かれている記事などを見ていると、ブラウザによって、文字入力時などのキー操作や挙動が若干違うという事が書かれています。 一番問題になっていた、コピペができないブラウザがあるとの事だったので、GoogleChrome、Safari、FirefonをMacですが確認したところ、この3つに関しては同じ挙動をしているようでした。 おそらく、スマホアプリなどで使われるアプリ内ブラウザや、ossを利用した独自ブラウザなどにおいて、それぞれの挙動が存在するのだと思った。

エンジニア視点からのアプローチ

何だか新しく覚えた機能は、早速でも使ってみたくなるのが、エンジニアの特性。 個人的に、次のような場合はどうするか(どうなるか)というのをいくつか紹介して

focus対応

focus()は普通に対応できますが、キャレット(カーソル位置)が、要素内の文字列の先頭になります。 それを末尾に移動させるには、次のコードでできます。 const elm = document.querySelector(".contenteditable") elm.focus() const selection = window.getSelection() const range = document.createRange() const offset = elm.innerText.length range.setStart(elm.firstChild, offset) range.setEnd(elm.firstChild, offset) selection.removeAllRanges() selection.addRange(range) 1行目のセレクタを該当のcontenteditable要素に書き換えるだけで、行末のキャッレトフォーカスが実現できます。

内部の文字列やDOM構造の取得

これは非常に簡単で、文字列だけをしゅとくしたければ、 document.querySelector(".contenteditable").textContent DOM構造を取得したければ、 document.querySelector(".contenteditable").innerHTML こちらで内容取得が柔軟に行えます。 さらに、内部DOMを分解調査などもしやすいので、悪くないですね。 ※DOM構造をコピペした場合は、style属性などが、必要以上にくっついてくるので、これらの精査をする必要がある場合もあるかも。

入力イベントなどの可否

inputやtextareaと同様に、次のイベント達が正常に動作するか調べてみました。
focus : OK blur : OK change : NG input : OK keypress : OK
残念ながら、onchangeイベントが動作しませんでした。 inputイベントをうまくフラグ的に処理して、blurイベント発火で独自にonchange発火を取得するしかないですかね?

inputのように改行をさせないようするには

inputとtextareaのそれぞれのタグを使い分けるには、改行を含むかどうかというポイントがあります。 contenteditableをtrueにすると、自由に改行ができてしまう、いわゆるtextarea状態になってしまうので、 inputタグのように1行しか入力させたくない場合はどうすればいいかというと、 まず簡易に考えた、cssでのwhite-space:nowrapをセットするだけだと、改行されてしまう。 これは、contenteditableが改行でdivタグを追加する仕様だからである。 他のサイトで色々と研究されていて、keypressイベントなどで、enterを発火させるといいのだが、 document.querySelector(".contenteditable").addEventListener("keypress" , ((e)=>{ console.log("keypress", e.keyCode) if(e.keyCode === 13){ e.preventDefault() } })) コピペ時にenterを取り除く対応もしなければ十分とは言えない。 ペーストを禁止させるのは、以下のイベントで簡単にセットできる。 document.querySelector(".contenteditable").addEventListener("paste" , ((e)=>{ console.log("paste") e.preventDefault() }))

formとして送信したい場合

formタグを使って、action属性で、サーバーの受取用APIなどに、入力データを送りたい場合は、いくつかの方法があります。 1. 普通にformタグを作って、サーバーに操作するtextarea(隠し要素)に内包するDOMをinputイベントで自動挿入して、formのsubmitで送信する。 2. new FormData()を使って、JS側でサーバー送信を行う。 // Sample const formData = new FormData(); formData.append("name", document.querySelector(".name").textContent); 3. JSのAjaxを使って柔軟にサーバーへのデータ送信をする。

あとがき

contenteditableを使うと、昔からある、iframeを使ったdesignModeという、ブログ記事などでよく使われている文字色を変えたり画像を貼り付けたりという操作と全く同じことが、単一タグ内でできてしまう。 確かにこれを便利に使えるようになると、かなりのインタラクティブなWebアプリ構築が可能になりそうだ。 世の中には、かなり使われている機能なのかもしれないが、今更この機能を知ったので、調査も含めて自分なりの備忘録ブログを書いておきました。 こういう調査するの、楽しいね。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ