Signatur
Beschreibung
Das dragstart-Event ist das erste Ereignis der HTML Drag and Drop API. Es wird am Quell-Element ausgelöst, sobald der Benutzer mit dem Ziehen beginnt – bei Elementen mit draggable="true", bei Links, Bildern oder bei markiertem Text. Das Event ist vom Typ DragEvent, steigt im DOM auf (bubbles) und lässt sich abbrechen (cancelable).
Im dragstart-Handler legt man fest, was gezogen wird: Über event.dataTransfer.setData() hinterlegt man die Nutzdaten (z. B. eine ID oder einen Text), mit effectAllowed bestimmt man die erlaubten Operationen (copy, move, link), und mit setDragImage() kann ein eigenes Vorschaubild gesetzt werden. Nur in dragstart (und drop) ist der Datenspeicher beschreibbar bzw. lesbar – in dragover oder dragenter sind nur die Typen sichtbar.
Ruft man event.preventDefault() auf, wird der Ziehvorgang komplett abgebrochen. Das ist nützlich, um das Ziehen situationsabhängig zu verhindern (z. B. bei gesperrten Einträgen). Alternativ zur Methode addEventListener kann auch die Eigenschaft ondragstart bzw. das HTML-Attribut ondragstart genutzt werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Event-Name "dragstart". |
|
| $handler Pflicht | (event: DragEvent) => void | Callback, das ein DragEvent erhält. Wichtigste Eigenschaft: event.dataTransfer (DataTransfer). |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie capture, once, passive oder signal. passive: true verhindert, dass preventDefault() wirkt. |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler erhält ein DragEvent; ein Aufruf von preventDefault() bricht den Ziehvorgang ab.Beispiele
Daten beim Ziehstart hinterlegen (addEventListener)
// HTML: <li id="task-42" draggable="true">Bericht schreiben</li>
const item = document.getElementById('task-42');
item.addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', item.id);
event.dataTransfer.effectAllowed = 'move';
item.classList.add('is-dragging');
console.log('Ziehen gestartet:', item.id);
});
item.addEventListener('dragend', () => {
item.classList.remove('is-dragging');
});
Event-Delegation für eine sortierbare Liste mit Drop-Ziel
// HTML: <ul id="list"><li draggable="true" data-id="1">A</li>...</ul>
// <div id="trash">Papierkorb</div>
const list = document.getElementById('list');
const trash = document.getElementById('trash');
list.addEventListener('dragstart', (event) => {
const li = event.target.closest('li[draggable]');
if (!li) return;
// Gesperrte Einträge dürfen nicht gezogen werden
if (li.dataset.locked === 'true') {
event.preventDefault();
return;
}
event.dataTransfer.setData('application/x-item-id', li.dataset.id);
});
trash.addEventListener('dragover', (event) => event.preventDefault()); // Drop erlauben
trash.addEventListener('drop', (event) => {
event.preventDefault();
const id = event.dataTransfer.getData('application/x-item-id');
list.querySelector(`[data-id="${id}"]`)?.remove();
console.log(`Eintrag ${id} gelöscht`);
});
Eigenes Drag-Vorschaubild über die on-Property
const card = document.querySelector('.card');
const ghost = document.createElement('div');
ghost.textContent = '📦 1 Datei';
ghost.style.cssText = 'position:absolute;top:-1000px;padding:4px 8px;background:#333;color:#fff';
document.body.append(ghost);
card.ondragstart = (event) => {
event.dataTransfer.setData('text/plain', card.dataset.file ?? 'datei.txt');
event.dataTransfer.setDragImage(ghost, 10, 10);
};
// Handler später wieder entfernen
// card.ondragstart = null;
Listener mit AbortController wieder entfernen
const box = document.querySelector('#box');
const controller = new AbortController();
const onDragStart = (event) => {
event.dataTransfer.setData('text/plain', 'box');
console.log('dragstart');
};
box.addEventListener('dragstart', onDragStart, { signal: controller.signal });
// Variante 1: klassisch
// box.removeEventListener('dragstart', onDragStart);
// Variante 2: über das Signal
controller.abort();
// Wichtig · Fallstricke
- draggable nicht vergessen: Normale Elemente (z. B.
div,li) lösendragstartnur mitdraggable="true"aus. Links, Bilder und Textauswahlen sind standardmäßig ziehbar. - Firefox: Ohne
dataTransfer.setData()startet Firefox bei manchen Elementen keinen Ziehvorgang – immer mindestens einen Datensatz setzen. - Drop-Ziel:
dragstartallein reicht nicht; das Ziel muss indragover(und ggf.dragenter)preventDefault()aufrufen, sonst wirddropnie ausgelöst. - Datenschutzmodus:
getData()liefert nur indragstartunddropWerte; indragoverist nurdataTransfer.typeslesbar. - Touch-Geräte: Die native Drag and Drop API wird auf Mobilgeräten nur eingeschränkt unterstützt (iOS Safari ab 15, Android-Browser teilweise). Für Touch sind oft Pointer Events oder Bibliotheken nötig.
- Sicherheit: Daten aus
dropkönnen von fremden Quellen (andere Tabs, Anwendungen) stammen – vor dem Einfügen ins DOM niemals ungeprüft perinnerHTMLverwenden (XSS). setDragImage()benötigt ein im DOM gerendertes Element oder ein geladenes Bild; ein nicht sichtbares/ungerendertes Element wird in manchen Browsern ignoriert.