Blog/NotesConcept

Understanding popstate event in Single Page Applications (SPAs)

A Quick guide about popstate event in JavaScript, If you’ve ever hit the back button in your browser and wondered how your Single-Page Application knows which view to render, this guide is for you.

Intermediate

Vijay Sai Krishna vsuri

Last Updated Feb 21, 2026


Understanding popstate event in Single Page Applications (SPAs)

Understanding popstate in Single Page Applications (SPAs)

We'll demystify the popstate event, explore examples in vanilla JavaScript, and then compare how libraries like React Router handle it under the hood.

The Basics: What is popstate in JavaScript?

The popstate event is fired on the window whenever the active history entry changes. This usually happens when the user clicks Back or Forward in the browser

window.addEventListener("popstate", (event) => {
  console.log("Location changed to:", window.location.pathname);
  console.log("State object:", event.state);
});
Important notes:
  • Unlike hashchange, popstate deals with the History API (pushState, replaceState, back, forward, go).
  • It does not fire when you call pushState or replaceState directly.
  • It only fires on user navigation or when you explicitly call history.back(), history.forward(), etc.
 

A Simple Example

Imagine a single-page app with two pages:

<button id="page1">Go to Page 1</button>
<button id="page2">Go to Page 2</button>
<div id="content"></div>
const content = document.getElementById("content");

function renderPage(page) {
  content.textContent = `You are on ${page}`;
}

document.getElementById("page1").onclick = () => {
  history.pushState({ page: "Page 1" }, "", "/page1");
  renderPage("Page 1");
};

document.getElementById("page2").onclick = () => {
  history.pushState({ page: "Page 2" }, "", "/page2");
  renderPage("Page 2");
};

window.addEventListener("popstate", (event) => {
  if (event.state) {
    renderPage(event.state.page);
  }
});

Multi-Iframe Considerations

  • Iframe Isolation: Each iframe has its own history stack.
  • Parent ↔ Iframe Independence: Navigation in the parent doesn’t affect the iframe and vice versa.
  • Same-Origin Only: Direct history manipulation only works within same-origin iframes.
  • Cross-Origin Communication: Use postMessage for syncing history between origins.
  • Programmatic Calls: Just like in single-window apps, pushState/replaceState don’t trigger popstate.

To synchronize navigation across iframes, use a communication layer with postMessage.

Direct URL Access: How SPAs Handle It

Question:

👉 "If I open /page2 directly in the browser, how does my SPA know what to render?"

1. Server Responsibility

  • There’s no physical /page2.html
  • The server is configured to always return index.html (History API Fallback)

2. Client Responsibility

  • Once index.html loads:
  • Your SPA boots up and looks at window.location.pathname
  • The router (e.g. React Router) matches the route and renders the correct component

Example (React Router)

<BrowserRouter>
  <Routes>
    <Route path="/page1" element={<Page1 />} />
    <Route path="/page2" element={<Page2 />} />
  </Routes>
</BrowserRouter>
Opening <code>/page2</code> loads <code>index.html</code>, then React Router handles the routing.

If the server isn’t configured: You’ll get a 404 error, since the server looks for /page2/index.html and doesn’t find it.

Solution: Configure the server to always return index.html.

How React Router Handles This

React Router (v6 and above) leverages the History API just like your vanilla JS examples, but with abstraction:

Features:

  • Wraps manual event handling behind a declarative API
  • Provides components like <Link> and hooks like useNavigate()
  • Automatically listens to popstate and re-renders the correct component tree

Example

import { BrowserRouter, Routes, Route, Link } from "react-router-dom";

export default function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/page1">Page 1</Link>
        <Link to="/page2">Page 2</Link>
      </nav>
      <Routes>
        <Route path="/page1" element={<div>You are on Page 1</div>} />
        <Route path="/page2" element={<div>You are on Page 2</div>} />
      </Routes>
    </BrowserRouter>
  );
}
<code>React Router</code> saves you from writing boilerplate like:
  • Listening for popstate
  • Managing route state
  • Manually rendering based on location.pathname

Key Takeaways

  1. popstate is triggered on browser history navigation, not on pushState/replaceState
  2. In multi-iframe apps, popstate is scoped to the iframe/window
  3. SPAs render correctly on direct links by:
    1. Server always returning index.html (History API fallback)
    2. Client router rendering based on window.location.pathname
  4. React Router simplifies this with an elegant, declarative API

Further Reading 

Love this Blog? Share it Now!

Help others discover this resource

About the Author

Vijay Sai Krishna vsuri


Learn Next

Featured

20 Most Asked Custom Hooks in React for Interviews

Top 10 React Performance Optimization Techniques25 Top JavaScript Interview Questions for BeginnersHow to create custom useInfiniteScroll Hook in ReactImplement useThrottle Custom Hook In React

Comments

Be the first to share your thoughts!

Guest User

Please login to comment

0 characters


No comments yet.

Start the conversation!

About the Author

Vijay Sai Krishna vsuri

Share your expertise

Publish a blog or quick notes on topics you know well — your write-up could be the answer someone needs before their next frontend interview.

Build your portfolio

Help the community

Sharpen your skills

Earn goodies

Other Related Blogs

What is javascript:void(0) and How it Works?

Anuj Sharma

Last Updated Jun 15, 2026

A comprehensive explanation about using javascript:void(0) in javascript. When to use javascript:void(0) and how it works with examples of using it with anchor tag.

Understand JavaScript Date Object with Examples (for JavaScript Interviews)

Anuj Sharma

Last Updated Jun 15, 2026

Go through different ways to display dates using javascript date object. It covers examples of date object usage to understand the main concepts of javascript date object.

How to Format Phone Number in JavaScript (JavaScript Interview)

Anuj Sharma

Last Updated Jun 15, 2026

Learn the best & quickest way to format phone number in JavaScript with or without country codes. This will help websites to show the phone numbers in a more human-readable format.

Ultimate guide to REST API calls using Fetch: Machine Coding Essential

Vivek Chavan

Last Updated Jun 15, 2026

You will get a clear understanding about working with any rest api and common concepts asked during interviews

25+ Top JavaScript Interview Questions and Answers For Beginners

Anuj Sharma

Last Updated Feb 6, 2026

A comprehensive list of important JavaScript Interview Questions and Answers for Beginners with a detailed explanation of the applied JavaScript concept for in-depth understanding.

How to convert RGB to HEX in JavaScript

Anuj Sharma

Last Updated Dec 17, 2025

A quick way to convert RGB to HEX in JavaScript that will help to do the CSS RGB to HEX color conversion programmatically

How to convert HEX to RGB in JavaScript

Anuj Sharma

Last Updated Dec 17, 2025

A quick way to convert HEX to RGB in JavaScript that will help to do the CSS HEX to RGB color conversion programmatically.

5 Different Ways to Reload Page in JavaScript (Frontend Interview)

Anuj Sharma

Last Updated Dec 16, 2025

Explore the 5 most efficient ways to refresh or reload page in JavaScript, similar to location.reload(true), and identify the appropriate use cases to reload window using JS programmatically.

Stay Updated

Subscribe to FrontendGeek Hub for frontend interview preparation, interview experiences, curated resources and roadmaps.

FrontendGeek
FrontendGeek

All in One Preparation Hub to Ace Frontend Interviews. Master JavaScript, React, System Design, and more with curated resources.

Consider Supporting this Free Platform

Buy Me a Coffee

Product

HomeFrontend InterviewFrontend JobsQuestionsNewInterview ExperienceBlogsToolsLeaderboardFrontendGeek Chrome extensionGet the extension on the Chrome Web Store

© 2026 FrontendGeek. All rights reserved