HTML ドラッグ&ドロップ API

HTML ドラッグ & ドロップインターフェイスにより、アプリケーションはブラウザーでドラッグ&ドロップ機能を使用することができます。ユーザーはマウスでドラッグ可能な要素を選択し、その要素をドロップ可能な要素へドラッグし、マウスボタンを離すことでドロップすることができます。ドラッグ操作の間、ドラッグ可能な要素の半透明の表示がマウスポインターに続きます。

ウェブサイト、拡張機能、XUL アプリケーションでは、ドラッグ可能にできる要素の種類、ドラッグ可能な要素が生成するフィードバックの種類、およびドロップ可能な要素をカスタマイズできます。

この HTML ドラッグ&ドロップの概要では、インターフェイスの説明、アプリケーションにドラッグ&ドロップのサポートを追加するための基本的なステップ、およびインターフェイスの相互運用性の要約が含まれています。

ドラッグイベント

HTML ドラッグ & ドロップ では DOM イベントモデルマウスイベント を継承した ドラッグイベント を使います。典型的なドラッグ操作は ユーザーがドラッグ可能な要素を選択したときと、ドロップ可能な要素に要素をドラッグしたとき、ドラッグ可能な要素を離したときに開始します。

ドラッグ操作のあいだ、いくつかのイベント種類が発生し、そのうちいくつかは dragdragover イベントのように、複数発生することもあります。

おのおのの ドラッグイベントタイプには関連したグローバルイベントハンドラーがあります。

イベント On イベントハンドラー 発生する条件…
drag ondrag …ドラッグ項目 (要素や選択テキスト) がドラッグされた場合
dragend ondragend …ドラッグ操作の終了 (マウスボタンを離したり、Esc キーを押したりした場合。詳しくはドラッグの終了を参照してください。)
dragenter ondragenter …ドラッグ項目が有効なドロップ対象に入った場合(Specifying Drop Targets を見てください)
dragexit ondragexit …要素がドラッグ操作の選択対象でなくなった場合
dragleave ondragleave …ドラッグ項目が有効なドロップ対象を離れた場合
dragover ondragover …ドラッグ項目が有効なドロップ対象にドラッグされた場合、数百ミリ秒ごとに
dragstart ondragstart …ユーザーが項目をドラッグ開始した場合(ドラッグ操作の開始 を見てください)
drop ondrop …項目が有効なドロップ対象にドロップされた場合(ドロップの実行 を見てください)

メモ: dragstartdragend イベントは、どちらも OS からブラウザーにファイルをドラッグしたときには発生しません。

インターフェイス

HTML ドラッグとドロップのインターフェイスは DragEvent, DataTransfer, DataTransferItem DataTransferItemList です。

DragEvent インターフェイスには、コンストラクターと dataTransfer プロパティ一つがあり、これは DataTransfer オブジェクトです。

DataTransfer オブジェクトはドラッグイベントの状態、例えば (copymove のような) ドラッグの種類や、ドラッグのデータ (1 つ以上の項目)や、各ドラッグ項目の MIME タイプのようなものを含んでいます。DataTransfer オブジェクトにはドラッグデータを追加・削除するメソッドもあります。

DragEventDataTransfer インターフェイスは、アプリケーションに HTML ドラッグ & ドロップ機能を追加するために必要な唯一のものです。 (Firefox では Gecko 独自拡張DataTransfer オブジェクトへ施していますが、この拡張機能は Firefox でのみ動作します。)

それぞれの DataTransfer オブジェクトには items プロパティがあり、これは DataTransferItem オブジェクトの list です。 DataTransferItem オブジェクトは単一のドラッグ項目を表し、それぞれが kind プロパティ (stringfile の値を取る) と項目の MIME タイプを表す type プロパティを持ちます。DataTransferItem オブジェクトにはドラッグ項目のデータを取得するメソッドもあります。

DataTransferItemList オブジェクトは DataTransferItem オブジェクトのリストです。このリストオブジェクトはリストにドラッグ項目を追加したり、リストからドラッグ項目を削除したり、ドラッグ項目のリストをクリアするメソッドを持ちます。

DataTransferDataTransferItem インターフェイスの主な違いは、前者が同期の getData() メソッドを使ってドラッグ項目のデータにアクセスするのに対し、後者は代わりに非同期のgetAsString() メソッドを使うことです。.

メモ: DragEventDataTransfer はデスクトップブラウザーでは広く対応していますが、 DataTransferItemDataTransferItemList インターフェイスのブラウザーの対応は限られています。相互運用性について、より詳しくは相互運用性を見てください。

Gecko-特有のインターフェイス

Mozilla と Firefox は、標準のドラッグ&ドロップのモデルに含まれていないいくつかの機能に対応しています。複数の項目や、文字列以外のデータ (ファイルなど) をドラッグしたりする補助になる便利な関数があります。詳しくは複数の項目のドラッグ&ドロップを参照してください。加えて、DataTransfer リファレンスページを見るとすべての Gecko 固有プロパティGecko 固有メソッドがわかります。

基本

この節は、アプリにドラッグ&ドロップ機能を追加する基本手順のまとめです。

ドラッグ可能なものを特定する

要素をドラッグ可能とするには、以下のコードのように draggable 属性と ondragstart のグローバルイベントハンドラを追加することが求められます:

<script>
  function dragstart_handler(ev) {
    // Add the target element's id to the data transfer object
    ev.dataTransfer.setData("text/plain", ev.target.id);
  }

  window.addEventListener('DOMContentLoaded', () => {
    // Get the element by id
    const element = document.getElementById("p1");
    // Add the ondragstart event listener
    element.addEventListener("dragstart", dragstart_handler);
  });
</script>

<p id="p1" draggable="true">この要素はドラッグできます。</p>

詳しくは、以下の記事を参照してください。

ドラッグするデータの定義

アプリケーションは、ドラッグ操作にいくつでもデータ項目を含めることが自由にできます。各データ項目は特定 typestring —よくあるのは text/html のような MIME タイプです。

ドラッグイベントはイベントのデータを格納するdataTransfer プロパティを持ちます。このプロパティ (これは DataTransfer オブジェクトです) にはドラッグデータを管理するメソッドもあります。setData() メソッドはドラッグデータに項目を追加するのに使用され、その例は下記の通りです。

function dragstart_handler(ev) {
  // 異なる種類のドラッグデータを追加する
  ev.dataTransfer.setData("text/plain", ev.target.innerText);
  ev.dataTransfer.setData("text/html", ev.target.outerHTML);
  ev.dataTransfer.setData("text/uri-list", ev.target.ownerDocument.location.href);
}
  • ドラッグ&ドロップで使用される一般的なデータ型の一覧 (テキスト、HTML、リンク、ファイルなど) については、推奨されるドラッグ型をご覧ください。
  • ドラッグデータについて詳しくは、ドラッグデータをご覧ください。

ドラッグ画像の定義

既定では、ブラウザーはドラッグ操作中にポインターの横に現れる画像を提供します。しかし以下の例のように、アプリケーションは setDragImage() メソッドでカスタム画像を定義できます。

function dragstart_handler(ev) {
  // 画像を作成し、ドラッグ画像として使う。
  // 注: "example.gif" は実際の画像の URL に変更してください。
  // でないと、既定ののドラッグ画像が使用されます。
  let img = new Image(); 
  img.src = 'example.gif'; 
  ev.dataTransfer.setDragImage(img, 10, 10);
}

ドラッグフィードバック画像について詳しくは、下記を参照してください。

ドラッグ効果の定義

dropEffect プロパティはドラッグ&ドロップ操作中のユーザーへのフィードバックを管理するのに使います。よくあるのはドラッグ中にどのカーソルをブラウザーが表示するかに影響します。例えば、ユーザーがドロップターゲット上に持ってきたとき、ブラウザーのカーソルは起こる動作の種類を示すことがあります。

3通りの効果が発生する可能性があります。

  1. copy はドラッグしたデータが現在の場所からドロップされる場所にコピーされることを示します。
  2. move はドラッグデータが現在の場所からドロップされる場所に移動されることを示します。
  3. link はドラッグデータが元からドロップ先にある種の関連や接続が作成されることを示します。

ドラッグ操作の間、ある効果はある場所にだけ許可されることを示すために、ドラッグ効果は変更される場合があります。

下記の例はこのプロパティの使い方を示します。

function dragstart_handler(ev) {
  ev.dataTransfer.dropEffect = "copy";
}

詳しくは以下を参照してください。

ドロップゾーンの定義

既定では、ブラウザーはほとんどの HTML 要素に何かがドロップされたとき、あらゆることが発生するのを防いでいます。この動作を変更して要素をドロップゾーンドロップ可能にするには、要素はondragoverondrop イベントハンドラー属性を持たねばなりません。

以下の例は、この属性の使い方と、各属性の基本的なイベントハンドラーを示しています。

<script>
function dragover_handler(ev) {
 ev.preventDefault();
 ev.dataTransfer.dropEffect = "move";
}
function drop_handler(ev) {
 ev.preventDefault();
 // 移動された要素のidを取得して、その要素をtargetのDOMに追加する
 var data = ev.dataTransfer.getData("text/plain");
 ev.target.appendChild(document.getElementById(data));
}
</script>

<p id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Zone</p>

各ハンドラーが preventDefault() を呼んで、このイベントが (タッチイベントポインターイベントなどに) 追加で処理されることを防いでいるのに注意してください

詳しくは、以下を参照してください。

ドロップ効果を扱う

drop イベントのハンドラーでは、アプリケーション固有の方法でドラッグデータを自由に処理できます。

ふつう、アプリケーションはgetData() メソッドでドラッグ項目を取得して、そのようよ処理します。加えて、アプリケーションのセマンティクスは dropEffect の値や修飾キーの状態により異なります。

下記の例では、ドラッグデータからソース要素の id を取得し、 id を使ってソース要素をドロップ要素に移動するドロップハンドラのを示しています。

<script>
function dragstart_handler(ev) {
 // 対象となる要素の id を DataTransfer オブジェクトに追加する
 ev.dataTransfer.setData("application/my-app", ev.target.id);
 ev.dataTransfer.dropEffect = "move";
}
function dragover_handler(ev) {
 ev.preventDefault();
 ev.dataTransfer.dropEffect = "move"
}
function drop_handler(ev) {
 ev.preventDefault();
 // 移動された要素の id を取得して、その要素を target の DOM に追加する
 const data = ev.dataTransfer.getData("application/my-app");
 ev.target.appendChild(document.getElementById(data));
}
</script>

<p id="p1" draggable="true" ondragstart="dragstart_handler(event)">This element is draggable.</p>
<div id="target" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Zone</div>

詳しくは、以下を参照してください。

ドラッグの終了

ドラッグ操作の終わりに、 dragend イベントがドラッグ元の要素で発生します。 — ドラッグが開始された対象の要素です。

このイベントはドラッグの完了とキャンセルのどちらでも発生します。 dragend イベントハンドラーは dropEffect プロパティの値をチェックしてドラッグ操作が成功したか否かを決定できます。

ドラッグ操作の終了を扱うことの詳細は、以下を参照してください。

相互運用性

DataTransferItem インターフェイスのブラウザー互換性テーブルに見られるように、ドラッグ&ドロップの相互接続性はデスクトップブラウザーでは相対的に広いです(サポートの少ないDataTransferItemDataTransferItemList インターフェイスを除いて)。このデータはモバイルブラウザーでのドラッグ&ドロップサポートはとても低いことも示しています。

例とデモ

関連情報