Start · Sprachen · JavaScript · Referenz · Window: popstate

Window: popstate

Ereignis

Wird am <code>window</code> ausgelöst, wenn der aktive Verlaufseintrag wechselt, z. B. durch Vor-/Zurück-Buttons oder <code>history.back()</code>.

seit JavaScript Baseline: alle Browser (HTML5 History API) Kategorie: webapi

Signatur

window.addEventListener("popstate", handler)

Beschreibung

Das Ereignis popstate wird am Window-Objekt ausgelöst, wenn sich der aktive Eintrag im Sitzungsverlauf ändert, während der Benutzer durch den Verlauf navigiert. Das passiert z. B., wenn er im Browser auf „Zurück“ oder „Vor“ klickt oder wenn Skripte history.back(), history.forward() oder history.go() aufrufen. Den Handler registrierst du mit window.addEventListener("popstate", handler) oder über die Eigenschaft window.onpopstate.

Wichtig für Single-Page-Anwendungen (SPA): popstate ist das Gegenstück zu history.pushState() und history.replaceState(). Mit diesen Methoden legst du Verlaufseinträge an oder änderst sie, ohne die Seite neu zu laden. Über popstate reagierst du dann auf die Navigation des Benutzers und stellst die passende Ansicht wieder her. Das Ereignisobjekt ist ein PopStateEvent. Seine Eigenschaft state enthält eine Kopie des Zustandsobjekts, das beim Anlegen des Eintrags übergeben wurde.

Achtung: Wenn du pushState() oder replaceState() selbst aufrufst, wird kein popstate ausgelöst. Das Ereignis entsteht nur durch eine Navigation im Verlauf. Wechselt der Benutzer zwischen zwei Einträgen desselben Dokuments, die sich nur im Fragment (#hash) unterscheiden, feuert popstate ebenfalls, und zwar vor hashchange.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "popstate".
$handler Pflicht (event: PopStateEvent) => void Callback, der ein PopStateEvent erhält. Die wichtigste Eigenschaft ist event.state: das Zustandsobjekt des Verlaufseintrags, zu dem navigiert wurde, oder null.
$options boolean | AddEventListenerOptions false Optionale Listener-Optionen wie once, passive oder signal (zum Entfernen per AbortController).

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler bekommt ein PopStateEvent mit den Eigenschaften state (any) und hasUAVisualTransition (boolean, noch nicht in allen Browsern verfügbar).

Beispiele

Einfaches SPA-Routing mit pushState und popstate

const render = (page) => {
  document.querySelector('#app').textContent = `Seite: ${page}`;
};

const navigate = (page) => {
  history.pushState({ page }, '', `/${page}`);
  render(page); // pushState löst kein popstate aus – selbst rendern
};

window.addEventListener('popstate', (event) => {
  // event.state ist null beim ursprünglichen Eintrag ohne Zustand
  const page = event.state?.page ?? 'start';
  console.log('Zurück/Vor zu:', page);
  render(page);
});

navigate('produkte');
navigate('kontakt');
history.back(); // löst popstate asynchron aus
Zurück/Vor zu: produkte

Anfangszustand mit replaceState setzen

// Damit auch der erste Eintrag einen Zustand hat
history.replaceState({ page: 'start', scrollY: 0 }, '');

window.onpopstate = ({ state }) => {
  console.log('Zustand:', JSON.stringify(state));
  if (state) window.scrollTo(0, state.scrollY);
};

history.pushState({ page: 'liste', scrollY: 400 }, '', '?liste');
history.back();
Zustand: {"page":"start","scrollY":0}

Listener per AbortController wieder entfernen

const controller = new AbortController();

const onPop = (event) => {
  console.log('Filter wiederherstellen:', event.state?.filter);
};

window.addEventListener('popstate', onPop, { signal: controller.signal });

// Später, z. B. beim Unmount einer Komponente:
controller.abort();
// Alternativ klassisch:
// window.removeEventListener('popstate', onPop);

Reihenfolge von popstate und hashchange

window.addEventListener('popstate', () => console.log('popstate'));
window.addEventListener('hashchange', () => console.log('hashchange'));

location.hash = '#abschnitt-2';
// Danach im Browser auf „Zurück“ klicken
popstate hashchange popstate hashchange

// Wichtig · Fallstricke

  • Kein Auslösen durch pushState/replaceState: Nach eigenen Aufrufen musst du die Ansicht selbst aktualisieren.
  • state kann null sein: Das gilt z. B. für den ersten Eintrag beim Seitenaufruf oder für Einträge, die über Hash-Links entstanden sind. Greif deshalb defensiv zu, etwa mit event.state?.x.
  • Zustand wird geklont: Das Zustandsobjekt wird mit dem Structured-Clone-Algorithmus gespeichert. Funktionen, DOM-Knoten und Ähnliches sind nicht erlaubt und führen zu einer DataCloneError-Ausnahme. Manche Browser begrenzen außerdem die Größe (Firefox z. B. auf etwa 16 MiB).
  • Beim Laden der Seite: Ältere Chrome- (vor 34) und Safari-Versionen (vor 10) haben popstate beim ersten Laden ausgelöst. Moderne Browser tun das nicht mehr.
  • Asynchron: history.back() und history.go() arbeiten asynchron. Das Ereignis feuert also nicht sofort nach dem Aufruf.
  • Dokumentwechsel: Führt die Navigation zu einem anderen Dokument, feuert popstate im neuen Dokument nicht. Reagiere dort stattdessen auf pageshow, auch wenn die Seite aus dem Back/Forward-Cache kommt.
  • Sicherheit: location und state können vom Benutzer manipuliert werden. Füge Werte daraus nie ungeprüft per innerHTML ein (Gefahr von XSS).
  • Ausblick: Die neuere Navigation API (navigation.addEventListener('navigate', …)) bietet ein umfassenderes Modell, wird aber noch nicht in allen Browsern unterstützt.