Signatur
Beschreibung
history.replaceState() verändert den aktuellen Eintrag im Sitzungsverlauf. Anders als history.pushState() legt die Methode keinen neuen Eintrag an. Die Länge von history.length bleibt also gleich, und der Zurück-Button führt weiterhin zur vorherigen Seite.
Typische Einsatzfälle:
- Filter-, Such- oder Sortierparameter in der URL aktuell halten, ohne den Verlauf mit vielen Einträgen zu füllen.
- Einen Anfangszustand für den ersten Eintrag einer Single-Page-App festlegen. Dieser wird später bei
popstategebraucht. - URLs aufräumen, etwa Tracking- oder Einmal-Parameter wie
?token=…nach dem Login entfernen. - Die Scrollposition oder den UI-Zustand im aktuellen Eintrag speichern, damit er bei der Rückkehr wiederhergestellt werden kann.
Der Aufruf löst kein popstate-Ereignis aus und lädt die Seite nicht neu. Der Browser prüft auch nicht, ob die neue URL auf dem Server existiert. Das gespeicherte Zustandsobjekt kann man danach über history.state lesen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $state Pflicht | any | Beliebiger Wert, der mit dem strukturierten Klon-Algorithmus serialisiert werden kann, z. B. ein Objekt, ein Array oder null. Er ist danach über history.state und event.state bei popstate erreichbar. Funktionen und DOM-Knoten sind nicht erlaubt. |
|
| $unused Pflicht | string | Wird aus historischen Gründen noch verlangt (früher title) und von Browsern ignoriert. Üblich ist eine leere Zeichenkette ''. |
|
| $url | string | URL | aktuelle URL | Neue URL für den aktuellen Eintrag, absolut oder relativ. Sie muss denselben Ursprung (Schema, Host, Port) wie das Dokument haben. Ohne Angabe bleibt die URL unverändert. |
Rückgabewert
undefined zurück.Beispiele
Filterparameter in der URL aktualisieren, ohne neuen Verlaufseintrag
const updateFilter = (key, value) => {
const url = new URL(location.href);
if (value) {
url.searchParams.set(key, value);
} else {
url.searchParams.delete(key);
}
history.replaceState(history.state, '', url);
};
// z. B. bei jeder Eingabe im Suchfeld
document.querySelector('#suche').addEventListener('input', (e) => {
updateFilter('q', e.target.value.trim());
});
Anfangszustand für eine Single-Page-App setzen
// Beim Start: aktuellen Eintrag mit Zustand versehen
history.replaceState({ view: 'home' }, '', location.pathname);
const navigate = (view) => {
history.pushState({ view }, '', `/${view}`);
render(view);
};
window.addEventListener('popstate', (event) => {
// Auch beim Zurückkehren zum ersten Eintrag ist event.state gesetzt
render(event.state?.view ?? 'home');
});
function render(view) {
console.log('Zeige Ansicht:', view);
}
console.log(history.state);
Einmal-Token nach dem Login aus der URL entfernen
// Aufruf z. B. über /dashboard?token=abc123&tab=stats
const url = new URL(location.href);
const token = url.searchParams.get('token');
if (token) {
sessionStorage.setItem('authToken', token);
url.searchParams.delete('token');
history.replaceState(null, '', url.pathname + url.search + url.hash);
}
console.log(location.href);
Scrollposition im aktuellen Eintrag merken
let timer;
window.addEventListener('scroll', () => {
clearTimeout(timer);
// Entprellen: nicht bei jedem Scroll-Ereignis schreiben
timer = setTimeout(() => {
history.replaceState({ ...history.state, scrollY: window.scrollY }, '');
}, 200);
});
window.addEventListener('popstate', (e) => {
if (e.state?.scrollY != null) window.scrollTo(0, e.state.scrollY);
});
// Wichtig · Fallstricke
- Gleicher Ursprung: Eine URL mit anderem Ursprung löst eine
SecurityError-DOMExceptionaus. Das gilt auch für den Wechsel vonhttpzuhttpsoder eine andere Subdomain. - Kein
popstate:replaceState()löst selbst keinpopstate-Ereignis aus. Die Oberfläche muss man also selbst neu zeichnen. - Klonbarkeit: Nicht klonbare Werte wie Funktionen, DOM-Knoten oder Klasseninstanzen mit Methoden werfen eine
DataCloneError. Klasseninstanzen verlieren beim Klonen außerdem ihren Prototyp. Browser begrenzen die Größe des Zustands, Firefox z. B. auf etwa 16 MiB. Große Daten gehören besser insessionStorageoder IndexedDB. - Drosselung: Browser begrenzen häufige Aufrufe. Safari und Chrome werfen ab etwa 100 Aufrufen in kurzer Zeit eine
SecurityErroroder ignorieren die Aufrufe. Bei Scroll- oder Eingabe-Ereignissen deshalb entprellen. - Serverseitiges Routing: Die neue URL wird nicht beim Server abgefragt. Wird die Seite neu geladen, muss der Server diese URL aber beantworten können, z. B. über einen Fallback auf
index.html. - Zweiter Parameter: Das frühere
title-Argument wird ignoriert. Den Seitentitel ändert man überdocument.title. - Kompatibilität: Wird von allen modernen Browsern unterstützt. In
file://-Kontexten und manchen Sandbox-iframes können Einschränkungen gelten. Die neuere Navigation API (navigation.navigate(url, { history: 'replace' })) ist eine Alternative, die aber noch nicht überall verfügbar ist.