JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
90: The History API
I see this all the time when developers start building Single Page Applications: they assume that calling history.pushState() is just a fancy way of telling the browser to "go to this page." They expect the browser to perform a navigation, fetch the new document from the server, and then run some JavaScript on the new page.
pushState doesn't actually "navigate"
Here is the crucial distinction: history.pushState() updates the URL in the address bar and adds an entry to the browser's session history, but it does not cause the browser to load a new page.
If you run window.history.pushState({page: 1}, "title", "/settings"); in your console right now, you'll see the URL change to /settings. But notice that the page didn't blink. No network request was sent to the server for a "settings" HTML file. Your current JavaScript state is still alive and well. If you had a counter running on the screen, it wouldn't reset. This is the "magic" that allows modern apps to feel like desktop software rather than a series of linked documents.
Managing the stack without the blink
Since the browser isn't doing the heavy lifting of loading a new page, you are now responsible for the UI. When you call pushState, you're essentially lying to the browser, saying, "We've moved to a new place," while you secretly stay on the same page. You then have to manually update the DOM to reflect that change.
Let's say you're building a photo gallery. When a user clicks a thumbnail, you don't want a full page reload (which is slow and jarring). Instead, you do this:
const openPhoto = (photoId) => {
// 1. Update the URL so the user can bookmark this specific photo
const url = `/photo/${photoId}`;
window.history.pushState({ id: photoId }, `Photo ${photoId}`, url);
// 2. Manually update the UI to show the photo
renderPhotoModal(photoId);
};
I'll also mention history.replaceState(). It does the exact same thing as pushState, but instead of adding a new entry to the history stack, it overwrites the current one. This is incredibly useful for things like search filters. If a user changes a "sort by" dropdown ten times, you probably don't want them to have to click the "Back" button ten times just to get back to the previous page. You'd use replaceState to keep the URL current without bloating the history.
Handling the "Back" button with popstate
Here is where most people get tripped up. Since pushState doesn't trigger a reload, the browser won't automatically "go back" to the previous state when the user hits the Back button; it will just change the URL back to the previous one. The page content will stay exactly as it was unless you're listening for it.
To fix this, you use the popstate event. This event fires whenever the user navigates through their session history (like clicking Back or Forward).
window.addEventListener('popstate', (event) => {
// The 'event.state' object is whatever we passed in as the first
// argument to pushState or replaceState.
if (event.state && event.state.id) {
renderPhotoModal(event.state.id);
} else {
closePhotoModal();
}
});
It's a bit of a mental shift. You aren't reacting to "pages" anymore; you're reacting to "state changes" that happen to be mirrored in the URL.
📋 Practical Task
Build a Client-Side Tab System with URL Syncing
Your goal is to create a simple tabbed interface where switching tabs updates the URL without refreshing the page, and clicking the browser's "Back" button reverts the active tab.
- Create three buttons (tabs): "Home", "About", and "Contact".
- Create a content
<div>that displays different text based on the active tab. - When a tab is clicked, use
history.pushStateto update the URL to/home,/about, or/contact. - Ensure the content
<div>updates immediately when a tab is clicked. - Implement a
popstateevent listener so that when the user clicks the browser's Back button, the UI switches back to the previous tab's content.
There are no comments for now.