Element: innerHTML プロパティ
Baseline
Widely available
*
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015年7月.
* Some parts of this feature may have varying levels of support.
Element オブジェクトの innerHTML プロパティは、要素内の HTML または XML のマークアップを取得したり設定したりします。
より正確に言えば、innerHTML は要素内の���れ子になった子 DOM 要素をシリアライズしたものを取得するか、要素内の DOM ツリーを置き換えるために解釈される HTML または XML を設定します。
要素の内容を置き換えるというより、文書に HTML を挿入するという場合には、insertAdjacentHTML() メソッドを使用してください。
DOM ツリーをプロパティから読み込んでシリアライズした場合、シャドウルートは含まれません。シャドウルートを含む HTML 文字列を取得したい場合は、 Element.getHTML() または ShadowRoot.getHTML() メソッドを使用する必要があります。
同様に、 innerHTML を使用して要素のコンテンツを設定する場合、 HTML 文字列はシャドウルートを含まない DOM 要素に解釈されます。
ですから、例えば <template> は、 shadowrootmode 属性が指定されているかどうかにかかわらず、 HTMLTemplateElement に解釈されます。
宣言的なシャドウルートが含まれた HTML 文字列から要素のコンテンツを設定するには、 Element.setHTMLUnsafe() または ShadowRoot.setHTMLUnsafe() を使用する必要があります。
値
要素の子孫を HTML にシリアライズしたものを含んだ文字列です。
innerHTML に値を設定すると、要素のすべての子孫を削除して、htmlString の文字列で与えられた HTML を解釈して構築されたノードに置き換えます。
null 値に設定すると、その null 値は空文字列 ("") に変換されるため、 elt.innerHTML = null は elt.innerHTML = "" と同等です。
例外
SyntaxErrorDOMException-
innerHTMLの値を、正しくない形の HTML の文字列を使用して設定しようとした場合に発生します。 NoModificationAllowedErrorDOMException-
親が
Documentであるノードに HTML を挿入しようとした場合に発生します。
使用上のメモ
要素の HTML コンテンツの読み取り
innerHTML を読み取ると、ユーザーエージェン��が要素の子孫で構成される HTML または XML の断片をシリアライズします。結果として文字列が返ります。
let contents = myElement.innerHTML;
これで、 HTML のコンテンツのノードの HTML マークアップを見ることができます。
メモ: 返される HTML または XML の断片は、現在の要素の中身に基づいて生成されますので、返される断片のマークアップや整形方法は、元のページのマークアップと同じであるとは限りません。
要素の中身の置き換え
innerHTML の値を設定することで、既存の要素の内容を新しい内容に置き換えることが簡単にできます。
警告: 挿入される文字列に悪意のある内容が含まれる可能性がある場合、セキュリティ上のリスクになります。 ユーザーが提供したデータを挿入する場合は、無害化するライブラリーを使用するよう常に検討してください。こちらは挿入する前に無害化を行います。
例えば、文書の body 属性の内容を消去することで、文書の内容全体を消去することができます。
document.body.textContent = "";
この例は文書の現在の HTML マークアップを走査し、 "<" の文字を文字参照の "<" に置き換え、それによって本質的に HTML を生テキストに変換します。
そしてこれを <pre> で囲みます。そして、 innerHTML の値をこの新しい文字列に変更します。結果として、文書の内容がページ全体のソースコードの表示に置き換わります。
document.documentElement.innerHTML = `<pre>${document.documentElement.innerHTML.replace(
/</g,
"<",
)}</pre>`;
操作の詳細
innerHTML に値を設定すると、正確には何が起きるのでしょうか?これを行うと、ユーザーエージェントは以下のステップを追います。
- 指定された値は (文書型に基づいて) HTML または XML として解釈され、新しい一連の要素の DOM ノードを表す
DocumentFragmentオブジェクトの中に結果が入れられます。 - 中身を置き換えようとしている要素が
<template>要素である場合は、<template>要素のcontent属性を、ステップ 1 で生成された新しいDocumentFragmentで置き換えます。 - その他の要素はすべて、要素の内容を新しい
DocumentFragmentのノードで置き換えます。
HTML を要素に適用
innerHTML に値を設定すると、既存の要素の一つに新しい内容物を追加します。
例えば、新しいリスト項目 (<li>) を既存のリスト (<ul>) に追加することができます。
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
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 を使用している例は珍しくありません。これがサイト上の攻撃ベクトルになる可能性があり、潜在的なセキュリティリスクが生じます。
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 を使用するたびに、セキュリティリスクは残ります。
const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // アラートが表示される
このため、 innerHTML を使用する代わりに次のようにしてください。
- プレーンテキストを挿入する際には、代わりに
Node.textContentを使用する。これは渡されたコンテンツを HTML として解釈するのではなく、生のテキストとして挿入します。
警告:
プロジェクトに対して何らかの形のセキュリティレビューが行われた場合、 innerHTML は多くの場合で、コードが拒絶される結果になります。
例えば、ブラウザー拡張機能の中で innerHTML を使用した場合、拡張機能を addons.mozilla.org に提出すると、自動レビュープロセスを通過できないでしょう。
代替方法については、ページへ外部コンテンツを安全に挿入するを参照してください。
例
この例は innerHTML を使用して、ウェブページ上のボックス内にメッセージを記録するメカニズムを作成します。
JavaScript
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 など) についての情報を記録する第二のメソッドを追加します。
function logEvent(event) {
const msg = `Event <strong>${event.type}</strong> at <em>${event.clientX}, ${event.clientY}</em>`;
log(msg);
}
それから、これをログを収めるボックスの様々なマウスイベントのイベントハンドラーとして登録します。
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 はとても単純です。
<div class="box">
<div><strong>Log:</strong></div>
<div class="log"></div>
</div>
"box" クラスが付いた <div> は、単なるレイアウト用途のコンテナーであり、内容とその周りのボックスを表します。
クラスが "log" である <div> は、ログテキスト自身のコンテナーです。
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 |
|---|
| HTML # dom-element-innerhtml |
ブラウザーの互換性
関連情報
Node.textContentおよびHTMLElement.innerTextElement.insertAdjacentHTML()Element.outerHTML- HTML または XML を解釈して DOM ツリーへ:
DOMParser - DOM ツリーを XML 文字列へシリアライズ:
XMLSerializer Element.getHTML()ShadowRoot.getHTML()Element.setHTMLUnsafe()ShadowRoot.setHTMLUnsafe()