Element: innerHTML プロパティ

Element オブジェクトの innerHTML プロパティは、要素内の HTML または XML のマークアップを取得したり設定したりします。

要素の内容を置き換えるというより、文書に HTML を挿入するという場合には、insertAdjacentHTML() メソッドを使用してください。

要素の子孫を HTML にシリアライズしたものを含んだ文字列です。innerHTML に値を設定すると、要素のすべての子孫を削除して、htmlString の文字列で与えられた HTML を解釈して構築されたノードに置き換えます。

例外

SyntaxError DOMException

正しくない形の HTML の文字列を使用して innerHTML の値を設定しようとした場合に発生します。

NoModificationAllowedError DOMException

親が Document であるノードに HTML を挿入しようとした場合に発生します。

使用上のメモ

innerHTML プロパティは、ページの現在の HTML ソースを、ページが最初に読み込まれてから行われたあらゆる変更を含めて、見るために利用することができます。

要素の HTML コンテンツの読み取り

innerHTML を読み取ると、ユーザーエージェントが要素の子孫で構成される HTML または XML の断片をシリアライズします。結果として文字列が返ります。

js
let contents = myElement.innerHTML;

これで、 HTML のコンテンツのノードの HTML マークアップを見ることができます。

メモ: 返される HTML または XML の断片は、現在の要素の中身に基づいて生成されますので、返される断片のマークアップや整形方法は、元のページのマークアップと同じであるとは限りません。

要素の中身の置き換え

innerHTML の値を設定することで、既存の要素の内容を新しい内容に置き換えることが簡単にできます。

メモ: 挿入される文字列に悪意のある内容が含まれる可能性がある場合、セキュリティ上のリスクになります。 ユーザーが提供したデータを挿入する場合は、 Element.setHTML() を使用するよう常に検討してください。こちらは挿入する前に無害化を行います。

例えば、文書の body 属性の内容を消去することで、文書の内容全体を消去することができます。

js
document.body.innerHTML = "";

この例は文書の現在の HTML マークアップを走査し、 "<" の文字を HTML エンティティの "&lt;" に置き換え、それによって本質的に HTML を生テキストに変換します。そしてこれを <pre> で囲みます。そして、 innerHTML の値をこの新しい文字列に変更します。結果として、文書の内容がページ全体のソースコードの表示に置き換わります。

js
document.documentElement.innerHTML = `<pre>${document.documentElement.innerHTML.replace(
  /</g,
  "&lt;",
)}</pre>`;

操作の詳細

innerHTML に値を設定すると、正確には何が起きるのでしょうか?これを行うと、ユーザーエージェントは以下のステップを追います。

  1. 指定された値は (文書型に基づいて) HTML または XML として解釈され、新しい一連の要素の DOM ノードを表す DocumentFragment オブジェクトの中に結果が入れられます。
  2. 中身を置き換えようとしている要素が <template> 要素である場合は、 <template> 要素の content 属性を、ステップ 1 で生成された新しい DocumentFragment で置き換えます。
  3. その他の要素はすべて、要素の内容を新しい DocumentFragment のノードで置き換えます。

HTML を要素に適用

innerHTML に値を設定すると、既存の要素の一つに新しい内容物を追加します。

例えば、新しいリスト項目 (<li>) を既存のリスト (<ul>) に追加することができます。

HTML

html
<ul id="list">
  <li><a href="#">Item 1</a></li>
  <li><a href="#">Item 2</a></li>
  <li><a href="#">Item 3</a></li>
</ul>

JavaScript

js
const list = document.getElementById("list");

list.innerHTML += `<li><a href="#">Item ${list.children.length + 1}</a></li>`;

なお、innerHTML を使用して HTML 要素を追加すると(例えば el.innerHTML += "<a href='…'>link</a>")、以前設定したイベントリスナーを取り除くことになります。 つまり、この方法で HTML 要素を追加すると、以前設定したイベントリスナーで待ち受けすることができなくなります。

セキュリティの考慮事項

ウェブページにテキストを挿入するために innerHTML を使用している例は珍しくありません。これがサイト上の攻撃ベクトルになる可能性があり、潜在的なセキュリティリスクが生じます。

js
let name = "John";
// 'el' を HTML の DOM 要素と想定します
el.innerHTML = name; // この場合は無害

// …

name = "<script>alert('I am John in an annoying alert!')</script>";
el.innerHTML = name; // この場合は無害

これはクロスサイトスクリプティング攻撃のように見えますが、結果的には無害です。 HTML5 では innerHTML で挿入された <script> タグは実行するべきではないと定義しているからです。

しかし、次のように <script> を使わずに JavaScript を実行する方法もあるので、制御することができない文字列を設定するために innerHTML を使用するたびに、セキュリティリスクは残ります。

js
const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // アラートが表示される

このため、 innerHTML を使用する代わりに次のようにしてください。

  • Element.setHTML() で DOM に挿入する前にテキストを無害化する。
  • プレーンテキストを挿入する際には、代わりに Node.textContent を使用する。これは渡されたコンテンツを HTML として解釈するのではなく、生のテキストとして挿入します。

警告: プロジェクトに対して何らかの形のセキュリティレビューが行われた場合、 innerHTML は多くの場合で、コードが拒絶される結果になります。 例えば、ブラウザー拡張機能の中で innerHTML を使用した場合、拡張機能を addons.mozilla.org に提出すると、自動レビュープロセスを通過できないでしょう。 代替方法については、ページへ外部コンテンツを安全に挿入する (en-US)を参照してください。

この例は innerHTML を使用して、ウェブページ上のボックス内にメッセージを記録するメカニズムを作成します。

JavaScript

js
function log(msg) {
  const logElem = document.querySelector(".log");

  const time = new Date();
  const timeStr = time.toLocaleTimeString();
  logElem.innerHTML += `${timeStr}: ${msg}<br/>`;
}

log("Logging mouse events inside this container…");

log() 関数は Date オブジェクトから toLocaleTimeString() を使用して現在時刻を取得し、タイムスタンプとメッセージテキストから成る文字列を構築してログ出力を生成します。それから "log" クラスのボックスにメッセージを追加します。

MouseEvent ベースのイベント (mousedown, click, mouseenter など) についての情報を記録する第二のメソッドを追加します。

js
function logEvent(event) {
  const msg = `Event <strong>${event.type}</strong> at <em>${event.clientX}, ${event.clientY}</em>`;
  log(msg);
}

それから、これをログを収めるボックスの様々なマウスイベントのイベントハンドラーとして登録します。

js
const boxElem = document.querySelector(".box");

boxElem.addEventListener("mousedown", logEvent);
boxElem.addEventListener("mouseup", logEvent);
boxElem.addEventListener("click", logEvent);
boxElem.addEventListener("mouseenter", logEvent);
boxElem.addEventListener("mouseleave", logEvent);

HTML

この例の HTML はとても単純です。

html
<div class="box">
  <div><strong>Log:</strong></div>
  <div class="log"></div>
</div>

"box" クラスが付いた <div> は、単なるレイアウト用途のコンテナーであり、内容とその周りのボックスを表します。 クラスが "log" である <div> は、ログテキスト自身のコンテナーです。

CSS

以下の CSS が例の内容をスタイル付けします。

css
.box {
  width: 600px;
  height: 300px;
  border: 1px solid black;
  padding: 2px 4px;
  overflow-y: scroll;
  overflow-x: auto;
}

.log {
  margin-top: 8px;
  font-family: monospace;
}

結果

結果の内容はこのように見えます。 マウスを移動してボックスを出入りさせたり、中でクリックしたりすると、ログが出力されるのを見ることができます。

仕様書

Specification
DOM Parsing and Serialization
# dom-innerhtml-innerhtml

ブラウザーの互換性

BCD tables only load in the browser

関連情報