Signatur
Beschreibung
Das drag-Ereignis gehört zur HTML-Drag-and-Drop-API. Es feuert am Quellelement, also am Element, das gezogen wird. Das passiert fortlaufend, solange der Benutzer zieht: typischerweise alle 50–350 ms, auch wenn sich die Maus gerade nicht bewegt. Damit das Ereignis bei beliebigen Elementen auftritt, müssen sie mit draggable="true" ziehbar gemacht werden. Links, Bilder und Textauswahlen sind von Haus aus ziehbar.
Einen Listener registrierst du entweder mit element.addEventListener("drag", handler) oder über die Eigenschaft element.ondrag = handler. Der Handler bekommt ein DragEvent. Das Ereignis steigt auf (bubbles), deshalb eignet es sich gut für Event-Delegation auf einem gemeinsamen Elternelement oder auf document. Es lässt sich abbrechen: preventDefault() bricht in manchen Browsern den Ziehvorgang ab, das ist aber nicht einheitlich umgesetzt.
Typische Einsatzfälle sind visuelles Feedback während des Ziehens (zum Beispiel das Quellelement abdunkeln), das Mitschreiben der Zeigerposition über clientX/clientY oder Auto-Scrolling, wenn der Zeiger den Rand eines Containers erreicht. Der Ablauf der Ereignisse ist: dragstart → wiederholt drag (dazu am Ziel dragenter/dragover/dragleave) → drop am Ziel → dragend an der Quelle.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "drag". |
|
| $handler Pflicht | (event: DragEvent) => void | Callback, der bei jedem drag-Ereignis aufgerufen wird. Er erhält ein DragEvent mit dataTransfer, clientX, clientY und weiteren Eigenschaften. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie capture, once, passive oder signal (zum Entfernen per AbortController). |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler erhält ein DragEvent (erbt von MouseEvent). Das Ereignis steigt auf, ist abbrechbar und hat keine Standardaktion, die man gezielt verhindern müsste.Beispiele
Quellelement während des Ziehens hervorheben
// HTML: <div id="karte" draggable="true">Zieh mich</div>
const karte = document.querySelector('#karte');
karte.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', karte.id);
});
karte.addEventListener('drag', () => {
// Wird wiederholt ausgelöst – nur Klasse setzen, keine teure Logik
karte.classList.add('wird-gezogen');
});
karte.addEventListener('dragend', () => {
karte.classList.remove('wird-gezogen');
});
Zeigerposition gedrosselt protokollieren
const quelle = document.querySelector('[draggable="true"]');
let letzterLog = 0;
quelle.addEventListener('drag', (e) => {
const jetzt = performance.now();
if (jetzt - letzterLog < 200) return; // höchstens alle 200 ms
letzterLog = jetzt;
// Achtung: Firefox liefert hier 0/0
console.log(`Position: ${e.clientX}, ${e.clientY}`);
});
Auto-Scroll am Containerrand per Delegation
const liste = document.querySelector('#liste');
const RAND = 40;
liste.addEventListener('drag', (e) => {
if (e.clientY === 0) return; // Ende des Ziehvorgangs bzw. Firefox
const { top, bottom } = liste.getBoundingClientRect();
if (e.clientY < top + RAND) liste.scrollBy(0, -10);
else if (e.clientY > bottom - RAND) liste.scrollBy(0, 10);
});
on-Property nutzen und Listener wieder entfernen
const el = document.querySelector('#karte');
// Variante 1: on-Property (nur ein Handler möglich)
el.ondrag = (e) => console.log('zieht…', e.type);
el.ondrag = null; // wieder entfernen
// Variante 2: removeEventListener mit derselben Funktionsreferenz
const beimZiehen = () => console.log('zieht…');
el.addEventListener('drag', beimZiehen);
el.addEventListener('dragend', () => {
el.removeEventListener('drag', beimZiehen);
}, { once: true });
// Wichtig · Fallstricke
- Hohe Auslösefrequenz:
dragfeuert ständig. Halte den Handler schlank, drossle ihn bei Bedarf oder bündle DOM-Änderungen mitrequestAnimationFrame. - Koordinaten in Firefox: Firefox liefert bei
dragfürclientX/clientY/screenXseit Langem0(Bug 505521). Als Ausweg liest man die Koordinaten ausdragoveraufdocument. Auch Chromium meldet beim letztendragvordragendoft0,0. - Kein Zugriff auf Daten: Während
dragistdataTransferim geschützten Modus,getData()gibt also einen leeren String zurück. Daten setzt man indragstartund liest sie indrop. - Nicht das Ziel:
dragtritt nur an der Quelle auf. Für Ablageziele sinddragover(mitpreventDefault()) unddropzuständig. - Touch-Geräte: Auf Mobilgeräten wird die native Drag-and-Drop-API erst seit Kurzem und nur eingeschränkt unterstützt (iOS Safari ab 15, Android Chrome je nach Version). Für zuverlässige Touch-Bedienung sind Pointer Events meist die bessere Wahl.
- Dateien, die von außerhalb des Browsers hereingezogen werden, lösen kein
dragaus, weil die Quelle nicht im Dokument liegt.