入力フォームを増減 デザイン見本
ボタンクリックで入力フォームを動的に追加・削除する実装解説。createElement() + appendChild() / removeChild() を使ったコピペ用コードを掲載。
① 基本の追加 — createElement() と appendChild()
<button id="add-btn">入力欄を増やす</button>
<div id="form-area">
<label>連絡事項:<input type="text"></label>
</div>
#form-area {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
label {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
input[type="text"] {
padding: 6px 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
var addBtn = document.getElementById('add-btn');
var formArea = document.getElementById('form-area');
addBtn.addEventListener('click', function() {
var newLbl = document.createElement('label');
newLbl.textContent = '連絡事項:';
var newInp = document.createElement('input');
newInp.type = 'text';
newLbl.appendChild(newInp);
formArea.appendChild(newLbl);
});
document.createElement() で新しいHTML要素をメモリ上に生成し、appendChild() で親要素の末尾に追加します。label 要素に input を入れてから div に追加する順序が重要です。appendChild() を呼ぶまで要素はページに表示されません。
② 番号付きラベル — 追加するたびに番号が増える
<button id="add-btn">入力欄を増やす</button>
<div id="form-area">
<label>連絡事項(1):<input type="text"></label>
</div>
#form-area {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
label {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
input[type="text"] {
flex: 1;
padding: 6px 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
var addBtn = document.getElementById('add-btn');
var formArea = document.getElementById('form-area');
addBtn.addEventListener('click', function() {
var formNum = formArea.querySelectorAll('input').length + 1;
var newInp = document.createElement('input');
newInp.type = 'text';
var newLbl = document.createElement('label');
newLbl.textContent = '連絡事項(' + formNum + '):';
newLbl.appendChild(newInp);
formArea.appendChild(newLbl);
});
クリック時点の input 要素数を querySelectorAll(‘input’).length で取得し、+1した値をラベルの番号に使います。変数 formNum には入力欄の現在数 + 1 の値が入るため、既存の入力欄が2つあれば「(3)」が付いた新しい欄が生成されます。
③ 追加+削除 — ×ボタンで個別に削除
<button id="add-btn">入力欄を増やす</button>
<div id="form-area">
<div class="form-row">
<label>連絡事項:<input type="text"></label>
<span class="close-btn">×</span>
</div>
</div>
.form-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.close-btn {
cursor: pointer;
font-size: 18px;
color: #999;
padding: 2px 6px;
border-radius: 3px;
transition: color 0.2s, background 0.2s;
}
.close-btn:hover {
color: #e53e3e;
background: #fff5f5;
}
var addBtn = document.getElementById('add-btn');
var formArea = document.getElementById('form-area');
function makeRow() {
var wrap = document.createElement('div');
wrap.className = 'form-row';
var lbl = document.createElement('label');
lbl.textContent = '連絡事項:';
var inp = document.createElement('input');
inp.type = 'text';
lbl.appendChild(inp);
var closeBtn = document.createElement('span');
closeBtn.className = 'close-btn';
closeBtn.textContent = '\u00D7';
closeBtn.addEventListener('click', function() {
wrap.parentNode.removeChild(wrap);
});
wrap.appendChild(lbl);
wrap.appendChild(closeBtn);
return wrap;
}
var existingRows = formArea.querySelectorAll('.form-row');
for (var i = 0; i < existingRows.length; i++) {
(function(row) {
var closeBtn = row.querySelector('.close-btn');
if (closeBtn) {
closeBtn.addEventListener('click', function() {
row.parentNode.removeChild(row);
});
}
})(existingRows[i]);
}
addBtn.addEventListener('click', function() {
formArea.appendChild(makeRow());
});
要素を削除するには element.parentNode.removeChild(element) を使います。makeRow() 関数内でクロージャを活用して生成した wrap 変数を参照し、そのまま削除します。既存の行には初期化ループで後からイベントを設定します。即時実行関数(IIFE)で変数 row をスコープに閉じ込めることで、ループ内のクロージャ問題を回避しています。
④ テーブル行の追加+削除 — tbody への行操作
| 名前 | 備考 | |
|---|---|---|
| 山田 太郎 | サンプルデータ A | × |
| 鈴木 花子 | サンプルデータ B | × |
<button id="add-row-btn">行を増やす</button>
<table>
<thead>
<tr>
<th>名前</th>
<th>備考</th>
<th class="close-col"></th>
</tr>
</thead>
<tbody id="my-tbody">
<tr>
<td>山田 太郎</td>
<td>サンプルデータ A</td>
<td class="close-col"><span class="close-btn">×</span></td>
</tr>
</tbody>
</table>
table {
border-collapse: collapse;
width: 100%;
margin-top: 12px;
}
th, td {
border: 1px solid #e2e8f0;
padding: 8px 12px;
text-align: left;
font-size: 14px;
}
thead {
background: #4f46e5;
color: #fff;
}
tbody tr:nth-child(even) {
background: #f8f9fa;
}
.close-col {
width: 40px;
text-align: center;
border: none;
}
.close-btn {
cursor: pointer;
font-size: 16px;
color: #999;
padding: 2px 6px;
border-radius: 3px;
transition: color 0.2s, background 0.2s;
}
.close-btn:hover {
color: #e53e3e;
background: #fff5f5;
}
var addRowBtn = document.getElementById('add-row-btn');
var tbody = document.getElementById('my-tbody');
function makeTblRow() {
var newTr = document.createElement('tr');
var td1 = document.createElement('td');
td1.textContent = '新規データ';
var td2 = document.createElement('td');
td2.textContent = '備考欄';
var tdClose = document.createElement('td');
tdClose.className = 'close-col';
var closeBtn = document.createElement('span');
closeBtn.className = 'close-btn';
closeBtn.textContent = '\u00D7';
closeBtn.addEventListener('click', function() {
newTr.parentNode.removeChild(newTr);
});
tdClose.appendChild(closeBtn);
newTr.appendChild(td1);
newTr.appendChild(td2);
newTr.appendChild(tdClose);
return newTr;
}
var existingTrs = tbody.querySelectorAll('tr');
for (var i = 0; i < existingTrs.length; i++) {
(function(tr) {
var closeBtn = tr.querySelector('.close-btn');
if (closeBtn) {
closeBtn.addEventListener('click', function() {
tr.parentNode.removeChild(tr);
});
}
})(existingTrs[i]);
}
addRowBtn.addEventListener('click', function() {
tbody.appendChild(makeTblRow());
});
テーブルに行を追加する際は thead を含む table 要素ではなく、tbody 要素に対して appendChild() します。こうするとヘッダー行の後ろに正しく追加されます。各セルは createElement(‘td’) で生成し tr に順番に追加します。makeTblRow() 関数でまとめて処理すると、行の構造を統一できます。
当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

