• textContentとinnerHTMLは文字列をテキストとして置くかHTMLとして解析するかで使い分ける

textContentとinnerHTMLは文字列をテキストとして置くかHTMLとして解析するかで使い分ける

公開日: 執筆:佐藤

JavaScriptで文字だけを表示するならtextContentを使います。見出し、リンク、強調などのHTMLを文字列から組み立てる必要がある場合に限り、innerHTMLを候補にします。

二つの違いは、タグらしい文字が画面へ見えるかどうかだけではありません。textContentは内容を一つのテキストとして扱い、innerHTMLは文字列をHTMLとして解析し、要素の子を置き換えます。表示したい内容が文字なのか、文書構造なのかを先に決めます。

textContentは文字列をテキストとして置く

次のコードは、処理結果を示す仮例です。

<p id="message"></p>
var message = document.getElementById('message');
message.textContent = '<strong>受付中</strong>';

画面には<strong>受付中</strong>という文字が表示されます。strong要素は作られません。

W3CのDOM4では、要素のtextContentへ値を設定すると、既存の子を取り除き、空でない値なら一つのTextノードへ置き換える処理を定めています。文字列をHTMLとして解析する処理ではありません。

問い合わせ内容、検索語、商品名、利用者名のように、文字として表示する値へHTMLの役割を持たせる必要はありません。値の中に<や>があっても、それを文章の一部として見せたいならtextContentが目的に合います。

innerHTMLは文字列をHTMLとして解析する

同じ文字列をinnerHTMLへ設定すると、結果が変わります。

var message = document.getElementById('message');
message.innerHTML = '<strong>受付中</strong>';

この場合はstrong要素が作られ、「受付中」が強調された内容になります。W3CのDOM Parsing and Serializationは、innerHTMLを要素内容のマークアップを表す属性とし、値を設定すると、文字列を解析して作ったノードで内容を置き換えると定めています。

したがって、値に含まれる要素名や属性も、単なる表示文字ではありません。外部から受け取った値をそのまま渡すと、意図していない要素や属性まで文書へ入る可能性があります。HTMLを許可する目的、受け取る書式、許可する要素を決めていない値は、innerHTMLへ渡しません。

読み出した結果もテキストとマークアップで違う

次のHTMLから内容を読み出します。

<p id="status">現在は<strong>受付中</strong>です。</p>
var status = document.getElementById('status');

status.textContent;
// 現在は受付中です。

status.innerHTML;
// 現在は<strong>受付中</strong>です。

textContentは、対象要素の中にあるTextノードの内容を文書順に連結します。innerHTMLは、子要素を含む内容をHTMLの断片として直列化します。

画面に書かれた文言を調べたいならtextContent、要素を含むマークアップを受け取りたいならinnerHTMLです。どちらも同じ「中身」を返すという理解では、比較条件や保存内容を取り違えます。

一部だけを強調するならノードを分けて作る

文字と要素を一つの領域へ混在させるために、必ずHTML文字列を作る必要はありません。DOMの操作で役割ごとにノードを作れます。

var message = document.getElementById('message');
var label = document.createElement('strong');

label.textContent = '受付中';
message.textContent = '現在は';
message.appendChild(label);
message.appendChild(document.createTextNode('です。'));

この仮例では、「現在は」と「です。」をテキストとして置き、「受付中」だけをstrong要素にします。文言と文書構造を別の処理へ分けられるため、どの値をHTMLとして扱うかがコードから分かります。

一方、管理者が編集した定型のHTML断片を読み込み、まとまった構造として差し替える用途では、innerHTMLのほうが処理を短く書ける場合があります。短く書けることと、受け取った値をHTMLとして扱ってよいことは別の判断です。

innerHTMLへの追記は子要素を作り直す

次のような書き方は、末尾へ一要素だけを追加する処理に見えます。

message.innerHTML += '<span>確認済み</span>';

しかし、+=は現在のinnerHTMLを文字列として読み、その末尾へ文字列を足し、完成した値をinnerHTMLへ設定し直します。設定処理では、要素の内容が解析結果へ置き換わります。既存の子を残したまま、末尾へ一つのノードだけを追加する処理ではありません。

一要素を追加する目的なら、createElement()とappendChild()を使います。既存の内容をすべて差し替える目的なら、置換が起きることを理解したうえでtextContentまたはinnerHTMLを使います。追加と全置換を同じコードへ見せないことが、修正範囲を把握する助けになります。

表示値の出所と変更範囲を確認して選ぶ

選択の基準は、値をどこから受け取り、何として表示し、どこまで置き換えるかです。

確認すること textContentが合う場合 innerHTMLを検討する場合
表示する内容 文字だけ 要素と属性を含むHTML
値の扱い マークアップとして解析しない HTMLとして解析する
変更範囲 子を一つのTextノードへ置き換える 子を解析結果のノードへ置き換える
一部だけ要素化する必要 DOM操作で必要な要素を作る 管理したHTML断片をまとめて入れる

制作を委託する場合は、innerHTMLを使った箇所だけでなく、そこへ値を渡す処理も受け取ります。値の出所、HTMLを許可する理由、許可する書式、全置換される範囲が分からなければ、表示を直すたびに同じ判断をやり直すことになります。

最初の一手は、書き換える箇所を一つ選び、表示する値を「文字だけ」「HTMLを含む定型データ」のどちらかへ分けることです。文字だけならtextContentへ替え、要素が必要なら文字列を連結する前に、DOM操作で組み立てられないかを確認します。

戻る