Signatur
Beschreibung
Das Ereignis beforeunload wird am Window-Objekt ausgelöst, bevor die Seite entladen wird. Das passiert zum Beispiel beim Neuladen, beim Schließen des Tabs, beim Navigieren über einen Link oder beim Aufruf von location.href = …. Zu diesem Zeitpunkt ist das Dokument noch sichtbar und voll funktionsfähig, und das Entladen lässt sich an dieser Stelle noch abbrechen.
Der wichtigste Anwendungsfall ist der Schutz vor Datenverlust: Hat jemand in einem Formular ungespeicherte Änderungen, ruft der Handler event.preventDefault() auf. Der Browser zeigt dann einen eigenen, nicht anpassbaren Bestätigungsdialog („Seite verlassen? Änderungen werden eventuell nicht gespeichert“). Früher war es üblich, zusätzlich event.returnValue auf einen String zu setzen oder einen String aus der Funktion zurückzugeben. Das wird heute nur noch aus Kompatibilitätsgründen ausgewertet, und eigene Texte zeigt kein moderner Browser mehr an.
Den Handler registrierst du entweder mit window.addEventListener("beforeunload", handler) oder über die Eigenschaft window.onbeforeunload = handler. Das Ereignis ist ein BeforeUnloadEvent und erbt von Event. Registriere den Listener am besten nur, solange wirklich ungespeicherte Daten vorliegen, und entferne ihn danach wieder. Ein dauerhaft registrierter beforeunload-Listener kann nämlich verhindern, dass die Seite in den Back/Forward-Cache (bfcache) aufgenommen wird.
Zum Speichern von Daten oder für Statistik-Aufrufe am Ende einer Sitzung ist beforeunload nicht zuverlässig, vor allem auf Mobilgeräten. Besser geeignet sind hier visibilitychange (mit document.visibilityState === "hidden") oder pagehide, jeweils zusammen mit navigator.sendBeacon() oder fetch(…, { keepalive: true }).
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "beforeunload". |
|
| $handler Pflicht | (event: BeforeUnloadEvent) => void | string | Callback-Funktion, die das BeforeUnloadEvent erhält. Ein Aufruf von event.preventDefault() fordert den Bestätigungsdialog an. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie { once: true } oder { signal } (zum Entfernen über einen AbortController). |
Rückgabewert
addEventListener gibt nichts zurück. Innerhalb des Handlers steuert event.preventDefault() (veraltet auch: event.returnValue setzen oder einen String zurückgeben), ob der Browser einen Bestätigungsdialog zeigt.Beispiele
Warnung bei ungespeicherten Formulardaten
const form = document.querySelector('#editor');
const warnBeforeLeave = (event) => {
event.preventDefault();
// Legacy-Fallback für ältere Browser
event.returnValue = '';
};
// Listener erst bei der ersten Änderung aktivieren
form.addEventListener('input', () => {
window.addEventListener('beforeunload', warnBeforeLeave);
}, { once: true });
// Nach dem Speichern wieder entfernen
form.addEventListener('submit', () => {
window.removeEventListener('beforeunload', warnBeforeLeave);
});
Variante über die on-Property
let isDirty = false;
document.querySelector('textarea').addEventListener('input', () => {
isDirty = true;
});
window.onbeforeunload = (event) => {
if (!isDirty) return; // kein Dialog
event.preventDefault();
return ''; // Legacy: Rückgabewert löst ebenfalls den Dialog aus
};
// Deaktivieren:
// window.onbeforeunload = null;
Entfernen mit AbortController
const controller = new AbortController();
window.addEventListener('beforeunload', (e) => {
e.preventDefault();
}, { signal: controller.signal });
const save = async (data) => {
await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });
controller.abort(); // Listener entfernt, Seite darf wieder bfcache nutzen
console.log('Gespeichert, Warnung deaktiviert');
};
save({ text: 'Hallo' });
Besser für Analytics: visibilitychange statt beforeunload
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/analytics', JSON.stringify({ event: 'session_end', t: Date.now() }));
}
});
// Wichtig · Fallstricke
- Kein eigener Text: Moderne Browser (Chrome 51+, Firefox 44+, Safari 9.1+) ignorieren eigene Meldungen und zeigen nur ihren Standarddialog an.
- Benutzerinteraktion nötig: Der Dialog erscheint nur, wenn der Nutzer vorher mit der Seite interagiert hat (Sticky User Activation). Ohne Interaktion wird die Seite einfach verlassen.
- Legacy-Verhalten: Ältere Chrome-Versionen (vor 119) reagierten nicht auf
preventDefault()allein. Setze deshalb zusätzlichevent.returnValue = ''. - Keine Dialoge im Handler:
alert(),confirm()undprompt()werden währendbeforeunloadignoriert. - Unzuverlässig auf Mobilgeräten: Wenn der Nutzer die App wechselt oder das System den Tab beendet, wird das Ereignis oft gar nicht ausgelöst. Wichtige Daten solltest du deshalb bei
visibilitychangeoderpagehidesichern. - bfcache: Ein aktiver
beforeunload-Listener kann den Back/Forward-Cache blockieren. Registriere ihn nur bei Bedarf und entferne ihn danach. - Asynchrone Aufrufe (
await fetch) im Handler werden meist nicht mehr fertig ausgeführt. Nutze dafürnavigator.sendBeacon()oderfetchmitkeepalive: true. - In iframes zeigen manche Browser keinen Dialog oder nur dann, wenn der Frame selbst navigiert.