ボタンを押すたびにリストへ項目が増える、入力内容に応じて画面に要素が現れる——こうした「あとから HTML を組み立てる」処理は、JavaScript の document.createElement() と appendChild() で実現します。この記事では、要素を作る・中身を入れる・ページに追加する、という3ステップの基本から、属性やクラスの付け方、複数要素をまとめて追加するコツ、そしてつまずきやすい innerHTML との違いまで、初心者の方にも分かるように解説します。
目次
要素を追加する3つのステップ
JavaScript で新しい要素を画面に出すには、大きく次の3ステップを踏みます。それぞれ役割の違うメソッドを使います。
| ステップ | メソッド/プロパティ | 役割 |
|---|---|---|
| 1. 作る | document.createElement(タグ名) | 指定したタグの要素を新しく生成する |
| 2. 中身を入れる | element.textContent | 要素の中のテキストを設定する |
| 3. 追加する | parent.appendChild(子) | 既存の要素の子として画面に差し込む |
重要なのは、createElement() で作っただけの要素はまだ画面のどこにも存在しないということです。メモリ上に部品が用意されただけの状態で、appendChild() で既存の要素にくっつけて初めて表示されます。下の例で、ボタンを押すと li が1つずつ増える様子を確かめてみてください。
<button id="add">項目を追加</button>
<ul id="list"></ul>
button {
padding: 8px 16px;
font-size: 14px;
cursor: pointer;
}
ul {
margin-top: 12px;
padding-left: 20px;
}
li {
margin: 4px 0;
}
const button = document.getElementById("add");
const list = document.getElementById("list");
let count = 0;
button.addEventListener("click", () => {
count++;
// 1. 新しい li 要素を作る
const li = document.createElement("li");
// 2. 中身のテキストを入れる
li.textContent = "項目 " + count;
// 3. ul の子として追加する
list.appendChild(li);
});
ボタンがクリックされるたびに、createElement("li") で li を作り、textContent で文字を入れ、appendChild() で ul の中へ追加しています。この3ステップが、動的な要素生成の基本形です。
createElement で要素を作る
document.createElement() は、引数にタグ名("div"・"p"・"li" など)を文字列で渡すと、その要素を1つ生成して返します。返ってきた要素を変数で受け取り、続けて中身や見た目を整えていきます。
// p 要素を作る(この時点ではまだ画面に出ていない)
const p = document.createElement("p");
// テキストを入れる
p.textContent = "あとから追加された段落です";
// クラスや属性も付けられる
p.classList.add("note");
p.setAttribute("id", "intro");
クラスは classList.add()、その他の属性は setAttribute(名前, 値) で設定できます。href や src のような属性も同じ要領です。ここまではすべて「部品を組み立てている」段階で、まだ画面には反映されません。
textContent と innerHTML の違い
要素に中身を入れる方法には textContent と innerHTML があり、性質が異なります。使い分けを誤ると、意図しない表示やセキュリティ上の問題につながります。
| プロパティ | 扱い | 向いている用途 |
|---|---|---|
textContent | 渡した文字列をそのままの文字として表示(タグは無効化) | ただのテキストを入れる(基本はこちら) |
innerHTML | 渡した文字列をHTML として解釈して要素に変換 | 自分で用意した固定のHTML断片を入れる |
ユーザーが入力した文字や外部から取得した値を表示するときは、必ず textContent を使ってください。innerHTML にそのまま入れると、文字列に含まれる <script> などがそのまま動いてしまい、XSS(クロスサイトスクリプティング)という攻撃の入り口になります。中身がただの文字なら textContent、と覚えておくと安全です。
appendChild で画面に追加する
組み立てた要素は、既存の要素の appendChild() に渡して、その子要素の末尾として差し込みます。差し込み先は getElementById() や querySelector() で取得しておきます。
const box = document.getElementById("box");
const p = document.createElement("p");
p.textContent = "追加する段落";
// box の子として末尾に追加する
box.appendChild(p);
末尾ではなく特定の位置に入れたいときは、parent.insertBefore(新しい要素, 基準の要素) を使うと基準要素の直前に差し込めます。新しい書き方では append()(複数同時・文字列も可)や prepend()(先頭に追加)も使えますが、まずは appendChild() を基本として押さえておけば十分です。
複数の要素はDocumentFragmentでまとめて追加する
ループで多くの要素を作るとき、1つ作るたびに appendChild() でページへ追加すると、その都度ブラウザが再描画を行い、数が多いと動作が重くなることがあります。こうした場合は document.createDocumentFragment() という「一時的な入れ物」を使い、そこへまとめてから一度だけ本物の要素に追加します。
const list = document.getElementById("list");
const fruits = ["りんご", "みかん", "ぶどう"];
// 一時的な入れ物にためる
const fragment = document.createDocumentFragment();
fruits.forEach((name) => {
const li = document.createElement("li");
li.textContent = name;
fragment.appendChild(li); // ここではまだ画面に出ない
});
// 最後に一度だけ本物の ul へ追加(再描画は1回)
list.appendChild(fragment);
DocumentFragment は画面に追加すると中身だけが移動し、入れ物自体は残りません。そのため ul の中に余計な要素が増えることはなく、追加にかかる描画も1回で済みます。
要素が追加されないとき
追加先の要素が取得できているか確認する
もっとも多い原因は、appendChild() を呼ぶ相手(追加先)が null になっているケースです。getElementById() の指定が id と一致していないと null が返り、「Cannot read properties of null」というエラーになります。id のつづりや、大文字・小文字を見直してください。
スクリプトの読み込むタイミングを見直す
head 内などで HTML より先に JavaScript が実行されると、対象の要素がまだ存在せず取得に失敗します。script タグを </body> の直前に置くか、script に defer 属性を付けると、HTML が読み込まれたあとに実行されるようになり解決します。
同じ要素を使い回していないか確認する
appendChild() は、すでにページにある要素を渡すと「コピー」ではなく「移動」になります。1つの要素を複数の場所に追加したつもりでも、最後に追加した場所へ移動するだけで、増えません。それぞれの場所に表示したいときは、追加するたびに createElement() で新しく作るか、cloneNode(true) で複製してから追加します。
まとめ
createElement() と appendChild() による動的な要素生成は、JavaScript で画面を組み立てる基本です。要点を整理します。
createElement(タグ名)で要素を作る。この時点では画面に出ていない。- 中身は基本
textContent。ユーザー入力をinnerHTMLに入れない。 - クラスは
classList.add()、属性はsetAttribute()で付ける。 appendChild()で既存要素の子として追加して初めて表示される。- 大量に追加するときは
DocumentFragmentでまとめて1回で追加する。
まずは「作る・中身を入れる・追加する」の3ステップを手に馴染ませ、ボタンのクリックで要素を増やすところから試してみてください。