ドラッグ&ドロップ デザイン見本
HTML の draggable 属性と JavaScript のドラッグイベントを組み合わせて、アイテムの順番をリアルタイムで並び替えるUIの実装デモです。コピーしてすぐに使えるHTML・CSS・JSのコードを掲載しています。
① draggable=”true” — ドラッグ可能な要素にする
ボタンで draggable 属性を切り替えられます
draggable: true
- Task 1
- Task 2
- Task 3
- Task 4
<ul class="task-list">
<li class="task" draggable="true">Task 1</li>
<li class="task" draggable="true">Task 2</li>
<li class="task" draggable="true">Task 3</li>
<li class="task" draggable="true">Task 4</li>
</ul>
.task-list {
list-style: none;
padding: 0;
margin: 0 auto;
max-width: 320px;
}
.task {
padding: 10px 16px;
margin: 6px 0;
background: #f0f0f0;
border: 1px solid #ccc;
border-radius: 6px;
cursor: move;
}
HTML要素に draggable="true" を設定すると、その要素をマウスでつかんでドラッグできるようになります。デフォルトは draggable="false" でドラッグ不可です。CSSで cursor: move を設定するとカーソルが十字矢印に変わり、ユーザーに「動かせる要素である」ことを伝えられます。
② .dragging クラス — ドラッグ中の視覚フィードバック
ボタンで .dragging クラスを適用・解除できます
Task 1 の状態: ドラッグ中
- Task 1
- Task 2
- Task 3
- Task 4
<div class="task-stage">
<ul class="task-list">
<li class="task" draggable="true">Task 1</li>
<li class="task" draggable="true">Task 2</li>
<li class="task" draggable="true">Task 3</li>
<li class="task" draggable="true">Task 4</li>
</ul>
</div>
.task-stage {
background: #1a1a2e;
padding: 24px 20px;
border-radius: 12px;
}
.task-list {
list-style: none;
padding: 0;
margin: 0 auto;
max-width: 300px;
}
.task {
padding: 10px 14px;
margin: 6px 0;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
color: rgba(255,255,255,0.8);
cursor: move;
transition: opacity 0.2s, background 0.2s;
user-select: none;
}
.task.dragging {
opacity: 0.35;
background: rgba(148,163,184,0.18);
}
(function() {
var taskList = document.querySelector('.task-list');
var tasks = taskList.querySelectorAll('.task');
tasks.forEach(function(task) {
task.addEventListener('dragstart', function() {
task.className = 'task dragging';
});
task.addEventListener('dragend', function() {
task.className = 'task';
});
});
})();
dragstart はドラッグ開始時、dragend はドラッグ終了時(成否問わず)に発火します。開始時に .dragging クラスを付与して半透明・色変化させ、終了時に外すことで「今どのアイテムを動かしているか」を視覚的に伝えられます。opacity と background に transition を加えると切り替えが滑らかになります。
③ 並び替えの実装 — getBoundingClientRect() と insertBefore() でドロップ位置を判定
タスクをドラッグして順番を入れ替えてみてください
- ☰ Task 1
- ☰ Task 2
- ☰ Task 3
- ☰ Task 4
<ul class="task-list">
<li class="task" draggable="true">Task 1</li>
<li class="task" draggable="true">Task 2</li>
<li class="task" draggable="true">Task 3</li>
<li class="task" draggable="true">Task 4</li>
</ul>
.task-list {
list-style: none;
padding: 0;
margin: 0 auto;
max-width: 320px;
}
.task {
padding: 10px 16px;
margin: 6px 0;
background: #f0f0f0;
border: 1px solid #ccc;
border-radius: 6px;
cursor: move;
transition: opacity 0.2s, background 0.2s;
user-select: none;
}
.task.dragging {
opacity: 0.4;
background: #b0c4de;
}
(function() {
var taskList = document.querySelector('.task-list');
var tasks = taskList.querySelectorAll('.task');
var movingEl = null;
tasks.forEach(function(task) {
task.addEventListener('dragstart', function() {
movingEl = task;
task.className = 'task dragging';
});
task.addEventListener('dragend', function() {
movingEl.className = 'task';
movingEl = null;
});
task.addEventListener('dragover', function(e) {
e.preventDefault();
var targetEl = e.target;
if (targetEl !== movingEl) {
var rect = targetEl.getBoundingClientRect();
var midY = rect.top + rect.height / 2;
if (e.clientY > midY) {
taskList.insertBefore(movingEl, targetEl.nextSibling);
} else {
taskList.insertBefore(movingEl, targetEl);
}
}
});
});
})();
dragover イベントはドラッグ中の要素が別の要素の上を通過するたびに発火します。getBoundingClientRect() でホバー先の位置・サイズを取得し、縦の中心(top + height / 2)を算出します。マウスのY座標(e.clientY)が中心より下なら要素の後ろへ、上なら前へ insertBefore() で挿入します。末尾に挿入する場合は targetEl.nextSibling が null になるため、自動的にリストの最後へ追加されます。
当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

