Start · Sprachen · JavaScript · Referenz · DragEvent

DragEvent

Schnittstelle

Das <code>DragEvent</code>-Interface steht für ein DOM-Ereignis während einer Drag-and-Drop-Interaktion und stellt über <code>dataTransfer</code> die gezogenen Daten bereit.

seit JavaScript Baseline: alle Browser (Desktop); Mobile eingeschr Kategorie: webapi

Signatur

interface DragEvent extends MouseEvent

Beschreibung

DragEvent ist die Ereignisklasse der HTML-Drag-and-Drop-API. Sie erbt von MouseEvent und damit auch von UIEvent und Event. Deshalb stehen neben der zusätzlichen Eigenschaft dataTransfer auch Koordinaten wie clientX/clientY, Zusatztasten wie shiftKey oder altKey sowie target zur Verfügung.

Der Browser löst beim Ziehen die folgenden Ereignisse aus:

  • am gezogenen Element: dragstart, drag und dragend,
  • am Ablageziel: dragenter, dragover, dragleave und drop.

Über das DataTransfer-Objekt tauscht man die Daten zwischen Quelle und Ziel aus: Mit setData() legt man sie in dragstart ab, mit getData() liest man sie in drop aus. Dateien aus dem Betriebssystem erreicht man über dataTransfer.files. Damit ein Element überhaupt als Ablageziel gilt, muss man in dragover (und am besten auch in dragenter) event.preventDefault() aufrufen.

Man verwendet DragEvent zum Beispiel für sortierbare Listen, Kanban-Boards, Bereiche zum Hochladen von Dateien oder zum Verschieben von Inhalten zwischen Fenstern und Anwendungen. Ein Element wird ziehbar, wenn es das Attribut draggable="true" hat. Links, Bilder und markierter Text lassen sich schon standardmäßig ziehen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Nur für den Konstruktor new DragEvent(type, options): Name des Ereignisses, z. B. "dragstart" oder "drop".
$options DragEventInit {} Optionales Objekt mit allen Feldern von MouseEventInit (z. B. bubbles, cancelable, clientX) sowie dataTransfer (DataTransfer | null, Standard null).

Rückgabewert

Typ
DragEvent
Beschreibung
Eine neue DragEvent-Instanz. Die wichtigste zusätzliche Eigenschaft ist dataTransfer (DataTransfer | null, nur lesbar).

Beispiele

Einfaches Drag-and-Drop zwischen zwei Elementen

// HTML: <div id="karte" draggable="true">Aufgabe 1</div>
//       <div id="spalte">Erledigt</div>
const karte = document.getElementById('karte');
const spalte = document.getElementById('spalte');

karte.addEventListener('dragstart', (event) => {
  console.log(event instanceof DragEvent); // true
  event.dataTransfer.setData('text/plain', event.target.id);
  event.dataTransfer.effectAllowed = 'move';
});

// Ohne preventDefault() ist kein Drop möglich
spalte.addEventListener('dragover', (event) => {
  event.preventDefault();
  event.dataTransfer.dropEffect = 'move';
});

spalte.addEventListener('drop', (event) => {
  event.preventDefault();
  const id = event.dataTransfer.getData('text/plain');
  spalte.appendChild(document.getElementById(id));
  console.log(`Verschoben: ${id}`);
});
true Verschoben: karte

Dateien per Drag-and-Drop hochladen

const zone = document.querySelector('#upload-zone');

const hervorheben = (an) => zone.classList.toggle('aktiv', an);

zone.addEventListener('dragenter', (e) => { e.preventDefault(); hervorheben(true); });
zone.addEventListener('dragover', (e) => e.preventDefault());
zone.addEventListener('dragleave', (e) => {
  // Nur reagieren, wenn die Zone wirklich verlassen wird
  if (!zone.contains(e.relatedTarget)) hervorheben(false);
});

zone.addEventListener('drop', async (e) => {
  e.preventDefault();
  hervorheben(false);
  const dateien = [...e.dataTransfer.files];
  const formData = new FormData();
  dateien.forEach((datei) => formData.append('dateien', datei));
  const antwort = await fetch('/api/upload', { method: 'POST', body: formData });
  console.log(`${dateien.length} Datei(en) hochgeladen, Status ${antwort.status}`);
});
2 Datei(en) hochgeladen, Status 200

DragEvent per Konstruktor erzeugen (z. B. für Tests)

const ziel = document.createElement('div');
ziel.addEventListener('drop', (e) => {
  console.log(e.type, e.dataTransfer.getData('text/plain'), e.clientX);
});

const dt = new DataTransfer();
dt.setData('text/plain', 'Hallo');

const event = new DragEvent('drop', {
  bubbles: true,
  cancelable: true,
  clientX: 120,
  dataTransfer: dt
});
ziel.dispatchEvent(event);
drop Hallo 120

Eigenes Vorschaubild beim Ziehen setzen

const element = document.querySelector('[draggable="true"]');
const vorschau = new Image();
vorschau.src = '/img/drag-icon.png';

element.ondragstart = (event) => {
  event.dataTransfer.setDragImage(vorschau, 16, 16);
  event.dataTransfer.setData('text/uri-list', location.href);
};

element.ondragend = (event) => {
  console.log('Ergebnis:', event.dataTransfer.dropEffect); // 'none' bei Abbruch
};
Ergebnis: copy

// Wichtig · Fallstricke

  • Ohne preventDefault() kein Drop: Wird preventDefault() in dragover nicht aufgerufen, löst der Browser drop nie aus. Beim Ablegen von Dateien öffnet er sie dann einfach als neue Seite.
  • Geschützte Daten: getData() liefert nur in drop (und in dragstart) echte Werte. In dragenter/dragover befindet sich der Datenspeicher im geschützten Modus. Dort kann man nur dataTransfer.types prüfen.
  • dragleave flackert: Das Ereignis feuert auch beim Wechsel auf Kindelemente. Abhilfe schaffen die Prüfung von relatedTarget, ein Zähler oder pointer-events: none auf den Kindern.
  • Mobile Geräte: Auf Touch-Geräten wird die HTML-Drag-and-Drop-API erst seit iOS Safari 15 bzw. in neueren Android-Browsern unterstützt und ist dort teils eingeschränkt. Für Touch-Bedienung sind Pointer Events oft die zuverlässigere Wahl.
  • Synthetische Ereignisse: Ein per new DragEvent() erzeugtes Ereignis startet keinen echten Ziehvorgang des Browsers. Es eignet sich nur, um Handler auszulösen, etwa in Tests.
  • Sicherheit: Abgelegte Inhalte wie text/html oder Dateinamen stammen aus fremden Quellen. Man sollte sie nie ungeprüft per innerHTML einfügen, sonst droht XSS. Besser ist textContent oder vorheriges Bereinigen, z. B. mit DOMPurify.
  • Performance: drag und dragover feuern alle paar Millisekunden. Aufwendige Logik in diesen Handlern sollte man drosseln.