| この記事の要点 |
|
Drag and Drop API とは
HTML5 Drag and Drop API(DnD API)は、ブラウザがネイティブでサポートするドラッグ&ドロップ機構です。要素を別の場所にマウス/タッチで運んだり、デスクトップからファイルをブラウザに投げ込んだりできます。jQuery UI や独自実装に頼らずに、純粋な DOM イベントだけで実現できるのが利点です。
基本フロー
| 段階 | 発火イベント | 対象 | 主な処理 |
|---|---|---|---|
| 掴む | dragstart | ドラッグ元 | dataTransfer.setData() でデータをセット |
| 運ぶ | drag | ドラッグ元 | 連続発火。UI 演出に使う |
| 上を通過 | dragenter / dragover | ドロップ先 | preventDefault() 必須 |
| 離脱 | dragleave | ドロップ先 | ホバー演出を解除 |
| 離す | drop | ドロップ先 | dataTransfer.getData() で受け取り |
| 終了 | dragend | ドラッグ元 | クリーンアップ |
最小実装例
<div id="src" draggable="true" style="padding:1em;background:#cef">Drag me</div>
<div id="dst" style="padding:2em;border:2px dashed #999;margin-top:1em">Drop here</div>
<script>
const src = document.getElementById('src');
const dst = document.getElementById('dst');
src.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', 'hello');
e.dataTransfer.effectAllowed = 'move';
});
dst.addEventListener('dragover', (e) => {
e.preventDefault(); // ← これが無いと drop が発火しない
e.dataTransfer.dropEffect = 'move';
});
dst.addEventListener('drop', (e) => {
e.preventDefault();
const data = e.dataTransfer.getData('text/plain');
dst.textContent = 'Dropped: ' + data;
});
</script>
dataTransfer オブジェクト
ドラッグ元とドロップ先の間でデータを受け渡すのが event.dataTransfer です。
| プロパティ / メソッド | 用途 |
|---|---|
setData(type, value) | データを格納。type は MIME(text/plain, text/html, application/json 等) |
getData(type) | データ取得。drop ハンドラ内でのみ |
files | OS から D&D されたファイル(FileList) |
effectAllowed | 許可される動作 copy / move / link / all |
dropEffect | カーソル表示(copy/move/link/none) |
setDragImage(el, x, y) | ドラッグ中のサムネ画像を差し替え |
ファイルの D&D(最頻出ユースケース)
<div id="dropzone" style="padding:3em;border:2px dashed #888;text-align:center">
Drop files here
</div>
<script>
const zone = document.getElementById('dropzone');
['dragenter', 'dragover'].forEach(t => {
zone.addEventListener(t, (e) => {
e.preventDefault();
zone.style.background = '#eef';
});
});
['dragleave', 'drop'].forEach(t => {
zone.addEventListener(t, (e) => {
e.preventDefault();
zone.style.background = '';
});
});
zone.addEventListener('drop', async (e) => {
const files = e.dataTransfer.files; // FileList
for (const f of files) {
console.log(f.name, f.size, f.type);
// 例: 画像をプレビュー
if (f.type.startsWith('image/')) {
const url = URL.createObjectURL(f);
const img = new Image();
img.src = url;
zone.appendChild(img);
}
// 例: サーバへアップロード
const fd = new FormData();
fd.append('file', f);
await fetch('/upload', { method: 'POST', body: fd });
}
});
</script>
preventDefault を忘れる罠
仕様上、ブラウザはデフォルトでは「ドロップを禁止する」動作になっています。dragover で preventDefault() を呼ばないと drop イベントが発火しません。これが Drag and Drop API で最も多いハマりどころです。
// ❌ NG: drop が発火しない
dst.addEventListener('drop', handler);
// ✅ OK
dst.addEventListener('dragover', (e) => e.preventDefault());
dst.addEventListener('drop', handler);
並べ替え(ソート)UI の実装
<ul id="list">
<li draggable="true">Apple</li>
<li draggable="true">Banana</li>
<li draggable="true">Cherry</li>
</ul>
<script>
let dragEl = null;
document.querySelectorAll('#list li').forEach(li => {
li.addEventListener('dragstart', () => { dragEl = li; li.style.opacity = .4; });
li.addEventListener('dragend', () => { dragEl = null; li.style.opacity = 1; });
li.addEventListener('dragover', (e) => {
e.preventDefault();
const rect = li.getBoundingClientRect();
const after = (e.clientY - rect.top) > rect.height / 2;
li.parentNode.insertBefore(dragEl, after ? li.nextSibling : li);
});
});
</script>
フォールバック / 制約
- モバイル(iOS Safari など)はネイティブ DnD 非対応に近い。Pointer Events や touch イベントで自前実装が必要
- キーボード操作・スクリーンリーダー対応が弱い → アクセシビリティ重視なら
dnd-kitを採用 dataTransfer.setData('text/uri-list', url)で URL D&D に対応- セキュリティ上、別オリジン間でのファイルパス取得は禁止
モダンライブラリの選び方
| ライブラリ | 用途 | 特徴 |
|---|---|---|
| SortableJS | リスト並べ替え | Vanilla JS、フレームワーク非依存、軽量 |
| dnd-kit | React | アクセシビリティ良好、Tree / Kanban 対応、ヘッドレス |
| react-dnd | React | 古参、HTML5 backend と touch backend を切替 |
| vue.draggable.next | Vue 3 | SortableJS のラッパー |
| Interact.js | 汎用 | リサイズ・ジェスチャ込み、低レイヤ |
FAQ
Q: drop イベントが発火しません
A: 99% は dragover の preventDefault() 忘れです。dragenter でも入れておくと確実。
Q: スマホでドラッグできません
A: HTML5 DnD はモバイルでは動作が不安定です。SortableJS(touch サポートあり)や Pointer Events を用いた自前実装に切り替えてください。
Q: ドラッグ中の見た目を変えたい
A: dragstart で e.dataTransfer.setDragImage(canvasEl, 0, 0)。canvas に好きな画像を描いて差し替えます。
子ページ
子ページはありません
同階層のページ
- Canvas API
- Drag and Drop API
- History API
- WebStorage API
- File API
- System Information API
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09