この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:guest
更新日時:2026-06-11 07:12:00

タイトル: Drag and Drop API
SEOタイトル: HTML5 Drag and Drop API 完全ガイド(dragstart/drop/dataTransfer の使い方)

この記事の要点
  • HTML5 Drag and Drop API はブラウザネイティブのドラッグ&ドロップ機構。要素やファイルをマウス/タッチで運べる
  • ドラッグ元: draggable="true" 属性 + dragstartdataTransfer.setData()
  • ドロップ先: dragoverpreventDefault() 必須 → これがないと drop が発火しない
  • ファイル D&D は event.dataTransfer.files で取得(FileList
  • モダンライブラリの定番: SortableJS(リスト並べ替え)/ dnd-kit(React、アクセシブル)/ react-dnd

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 ハンドラ内でのみ
filesOS から 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 を忘れる罠

仕様上、ブラウザはデフォルトでは「ドロップを禁止する」動作になっています。dragoverpreventDefault() を呼ばないと 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-kitReactアクセシビリティ良好、Tree / Kanban 対応、ヘッドレス
react-dndReact古参、HTML5 backend と touch backend を切替
vue.draggable.nextVue 3SortableJS のラッパー
Interact.js汎用リサイズ・ジェスチャ込み、低レイヤ

FAQ

Q: drop イベントが発火しません
A: 99% は dragoverpreventDefault() 忘れです。dragenter でも入れておくと確実。

Q: スマホでドラッグできません
A: HTML5 DnD はモバイルでは動作が不安定です。SortableJS(touch サポートあり)や Pointer Events を用いた自前実装に切り替えてください。

Q: ドラッグ中の見た目を変えたい
A: dragstarte.dataTransfer.setDragImage(canvasEl, 0, 0)。canvas に好きな画像を描いて差し替えます。