SOLFIND
Web Lens
Portal home

Working with the History API - Web APIs | MDN

https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API • 154 KB fetched
Open original page


Working with the History API - Web APIs | MDN * Skip to main content * Skip to search HTML HTML: Markup language HTML reference * Elements * Global attributes * Attributes * See all… HTML guides * Responsive images * HTML cheatsheet * Date & time formats * See all… Markup languages * SVG * MathML * XML CSS CSS: Styling language CSS reference * Properties * Selectors * At-rules * Values * See all… CSS guides * Box model * Animations * Flexbox * Colors * See all… Layout cookbook * Column layouts * Centering an element * Card component * See all… JavaScript JS JavaScript: Scripting language JS reference * Standard built-in objects * Expressions & operators * Statements & declarations * Functions * See all… JS guides * Control flow & error handing * Loops and iteration * Working with objects * Using classes * See all… Web APIs Web APIs: Programming interfaces Web API reference * File system API * Fetch API * Geolocation API * HTML DOM API * Push API * Service worker API * See all… Web API guides * Using the Web animation API * Using the Fetch API * Working with the History API * Using the Web speech API * Using web workers All All web technology Technologies * Accessibility * HTTP * URI * Web extensions * WebAssembly * WebDriver * See all… Topics * Media * Performance * Privacy * Security * Progressive web apps Learn Learn web development Frontend developer course * Getting started modules * Core modules * MDN Curriculum * Check out the video course from Scrimba, our partner Learn HTML * Structuring content with HTML module Learn CSS * CSS styling basics module * CSS layout module Learn JavaScript * Dynamic scripting with JavaScript module Tools Discover our tools * Playground * HTTP Observatory * Border-image generator * Border-radius generator * Box-shadow generator * Color format converter * Color mixer * Shape generator About Get to know MDN better * About MDN * Advertise with us * Community * MDN on GitHub Blog Toggle sidebar * Web * Web APIs * History API * Working with the History API Theme * OS default * Light * Dark English (US) Remember language Learn more * Deutsch * English (US) * Español * Français * 日本語 * 한국어 * Português (do Brasil) * Русский * 中文 (简体) Working with the History API The History API enables a website to interact with the browser's session history: that is, the list of pages that the user has visited in a given window. As the user visits new pages, for example by clicking links, those new pages are added to the session history. The user can also move back and forth through the history using the browser's "Back" and "Forward" buttons. The main interface defined in the History API is the History interface, and this defines two quite distinct sets of methods: * Methods to navigate to a page in the session history: * History.back() * History.forward() * History.go() * Methods to modify the session history: * History.pushState() * History.replaceState() In this guide, we'll cover only the second set of methods. The pushState() method adds a new entry to the session history, while the replaceState() method updates the session history entry for the current page. Both these methods take a state parameter which can contain any serializable object . When the browser navigates to this history entry, the browser fires a popstate event, which contains the state object associated with that entry. The main purpose of these APIs is to support websites like Single-page applications , that use JavaScript APIs such as fetch() to update the page with new content, instead of loading a whole new page. In this article * Single-page applications and session history * Using pushState() * Using the popstate event * Using replaceState() * Complete History API example * See also Single-page applications and session history Traditionally, websites are implemented as a collection of pages. When users navigate to different parts of the site by clicking links, the browser loads a whole new page each time. While this is great for many sites, it can have some disadvantages: * It can be inefficient to load a whole page every time, when only part of the page needs to be updated. * It is hard to maintain application state when navigating across pages. For these reasons, a popular pattern for web apps is the single-page application (SPA). When a user clicks a link, the SPA performs the following steps: * Prevents the default behavior of loading a new page. * Fetches new content to display. * Updates the page with the new content. For example: js document.addEventListener("click", async (event) => { const creature = event.target.getAttribute("data-creature"); if (creature) { // Prevent a new page from loading event.preventDefault(); try { // Fetch new content const response = await fetch(`creatures/${creature}.json`); const result = await response.json(); // Update the page with the new content displayContent(result); } catch (err) { console.error(err); } } }); In this click handler, if the link contains a data attribute "data-creature" , then we use the value of that attribute to fetch a JSON file containing the new content for the page. The JSON file might look like this: json { "description": "Bald eagles are not actually bald.", "image": { "src": "images/eagle.jpg", "alt": "A bald eagle" }, "name": "Eagle" } Our displayContent() function updates the page with the JSON: js // Update the page with the new content function displayContent(content) { document.title = `Creatures: ${content.name}`; const description = document.querySelector("#description"); description.textContent = content.description; const photo = document.querySelector("#photo"); photo.setAttribute("src", content.image.src); photo.setAttribute("alt", content.image.alt); } The problem is that it breaks the expected behavior of the browser's "Back" and "Forward" buttons. From the user's point of view, they clicked a link and the page updated, so it looks like a new page. If they then press the browser's "Back" button, they expect to go to the state before they clicked the link. But as far as the browser is concerned, the last link didn't load a new page, so "Back" will take the browser to whichever page was loaded before the user opened the SPA. This is essentially the problem that pushState() , replaceState() , and the popstate event solve. They enable us to synthesize history entries, and to be notified when the current session history entry changes to one of these entries (for example, because the user pressed the "Back" or "Forward" buttons). Using pushState() We can add a history entry to the click handler above as follows: js document.addEventListener("click", async (event) => { const creature = event.target.getAttribute("data-creature"); if (creature) { event.preventDefault(); try { const response = await fetch(`creatures/${creature}.json`); const result = await response.json(); displayContent(result); // Add a new entry to the history. // This simulates loading a new page. history.pushState(result, "", creature); } catch (err) { console.error(err); } } }); Here, we're calling pushState() with three arguments: * result : This is the content we just fetched. It will be stored with the history entry, and later included as the state property of the argument passed to the popstate event handler. * "" : This is needed for backward compatibility with legacy sites, and should always be an empty string. * creature : This will be used as the URL for the entry. It will be shown in the browser's URL bar, and will be used as the value of the Referer header in any HTTP requests that the page makes. Note that this must be same-origin with the page. Using the popstate event Suppose the user performs the following steps: * Clicks a link in our SPA, so we update the page and add history entry A using pushState() . * Clicks another link in our SPA, so we update the page and add history entry B using pushState() . * Presses the "Back" button. Now the new current history entry is A, so the browser fires the popstate event, and the event handler argument includes the JSON that we passed to pushState() when we handled the navigation to A. This means we can restore the correct content with an event handler like this: js // Handle forward/back buttons window.addEventListener("popstate", (event) => { // If a state has been provided, we have a "simulated" page // and we update the current page. if (event.state) { // Simulate the loading of the previous page displayContent(event.state); } }); Using replaceState() There's one more piece we need to add. When the user loads the SPA, the browser adds a history entry. Because this was an actual page load, the entry has no state associated with it. So suppose the user does the following: * Loads the SPA, so the browser adds a history entry. * Clicks a link inside the SPA, so the click handler updates the page and adds a history entry with pushState() . * Presses the "Back" button. Now we want to go back to the SPA's initial state, but since this is a navigation in the same document, the page will not be reloaded, and since the history entry for the initial page has no state, we can't use popstate to restore it. The solution here is to use replaceState() to set the state object for the initial page. For example: js // Create state on page load and replace the current history with it const image = document.querySelector("#photo"); const initialState = { description: document.querySelector("#description").textContent, image: { src: image.getAttribute("src"), alt: image.getAttribute("alt"), }, name: "Home", }; history.replaceState(initialState, "", document.location.href); On page load, we collect all the parts of the page that we need to restore when the user returns to the starting point for the SPA. This has the same structure as the JSON we fetch when handling other navigations. We pass this initialState object into replaceState() , which effectively adds the state object to the current history entry. When the user returns to our starting point, the popstate event will contain this initial state, and we can use our displayContent() function to update the page. Complete History API example You can find this complete example at https://github.com/mdn/dom-examples/tree/main/history-api , and see the demo live at https://mdn.github.io/dom-examples/history-api/ . See also * History API * history global object Help improve MDN Yes No Learn how to contribute This page was last modified on Aug 1, 2025 by MDN contributors . View this page on GitHub • Report a problem with this content Clear filter input * History API * Guides * Working with the History API * Interfaces * History * PopStateEvent * Properties * Window .history * Events * Window: popstate Your blueprint for a better internet. * * * * * MDN * About * Blog * Mozilla careers * Advertise with us * MDN Plus * Product help Contribute * MDN Community * Community resources * Writing guidelines * MDN Discord * MDN on GitHub Developers * Web technologies * Learn web development * Guides * Tutorials * Glossary * Hacks blog * Website Privacy Notice * Telemetry Settings * Legal * Community Participation Guidelines Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license .

Links found on this page

  1. Skip to main content [direct]
  2. HTML: Markup language [direct]
  3. Elements [direct]
  4. Global attributes [direct]
  5. Attributes [direct]
  6. See all… [direct]
  7. Responsive images [direct]
  8. HTML cheatsheet [direct]
  9. Date & time formats [direct]
  10. See all… [direct]
  11. SVG [direct]
  12. MathML [direct]
  13. XML [direct]
  14. CSS: Styling language [direct]
  15. Properties [direct]
  16. Selectors [direct]
  17. At-rules [direct]
  18. Values [direct]
  19. See all… [direct]
  20. Box model [direct]
  21. Animations [direct]
  22. Flexbox [direct]
  23. Colors [direct]
  24. See all… [direct]
  25. Column layouts [direct]
  26. Centering an element [direct]
  27. Card component [direct]
  28. See all… [direct]
  29. JavaScript: Scripting language [direct]
  30. Standard built-in objects [direct]
  31. Expressions & operators [direct]
  32. Statements & declarations [direct]
  33. Functions [direct]
  34. See all… [direct]
  35. Control flow & error handing [direct]
  36. Loops and iteration [direct]
  37. Working with objects [direct]
  38. Using classes [direct]
  39. See all… [direct]
  40. Web APIs: Programming interfaces [direct]
  41. File system API [direct]
  42. Fetch API [direct]
  43. Geolocation API [direct]
  44. HTML DOM API [direct]
  45. Push API [direct]
  46. Service worker API [direct]
  47. Using the Web animation API [direct]
  48. Using the Fetch API [direct]
  49. Using the Web speech API [direct]
  50. Using web workers [direct]
  51. All web technology [direct]
  52. Accessibility [direct]
  53. HTTP [direct]
  54. URI [direct]
  55. Web extensions [direct]
  56. WebAssembly [direct]
  57. WebDriver [direct]
  58. Media [direct]
  59. Performance [direct]
  60. Privacy [direct]
  61. Security [direct]
  62. Progressive web apps [direct]
  63. Learn web development [direct]
  64. Getting started modules [direct]
  65. Core modules [direct]
  66. MDN Curriculum [direct]
  67. Check out the video course from Scrimba, our partner [direct]
  68. Structuring content with HTML module [direct]
  69. CSS styling basics module [direct]
  70. CSS layout module [direct]
  71. Dynamic scripting with JavaScript module [direct]
  72. Playground [direct]
  73. HTTP Observatory [direct]
  74. Border-image generator [direct]
  75. Border-radius generator [direct]
  76. Box-shadow generator [direct]
  77. Color format converter [direct]
  78. Color mixer [direct]
  79. Shape generator [direct]
  80. About MDN [direct]