Question
How to Modify the URL Without Reloading the Page in JavaScript
Question
I want to change the URL of the current page in JavaScript without causing the browser to reload the page.
For example, assigning a new value to window.location.href reloads the page:
window.location.href = "www.mysite.com/page2.php";
Is there a way to update only the path or other parts of the current URL after the domain without reloading?
If possible, I would also like to access or modify the part of the URL before the # hash.
Short Answer
By the end of this page, you will understand how JavaScript can update the browser URL without refreshing the page, when to use the History API versus the hash portion of the URL, and what restrictions apply when changing paths, query strings, and fragments.
Concept
The core concept behind this question is client-side URL manipulation.
Normally, when you assign a new value to window.location.href, the browser treats it as a navigation request. That means it loads a new page from the server.
However, modern browsers also provide the History API, which lets JavaScript update the URL shown in the address bar without reloading the page.
The two main methods are:
history.pushState(state, title, url)
history.replaceState(state, title, url)
These methods are useful in single-page applications, filters, tabs, dashboards, and search pages where the UI changes but a full page reload would be unnecessary.
Why this matters
Changing the URL without reloading is important because:
- users can bookmark the current app state
- the back and forward buttons can still work
- URLs can reflect selected filters, tabs, or views
- the page feels faster because it avoids full reloads
What you can change
You can update:
- the path, such as
/page2 - the query string, such as
?sort=price - the hash, such as
#section3
But there is an important rule:
- you can only use the History API for URLs on the same origin
- same origin means same protocol, host, and port
So this is allowed if you stay on the same site:
history.pushState({}, "", "/page2.php")
But changing to a different domain is not allowed with pushState.
Accessing the part before the hash
Yes, you can access the part before #.
For example:
const fullUrl = window.location.href;
const beforeHash = fullUrl.split("#")[0];
console.log(beforeHash);
You can also use the more reliable location parts:
console.log(location.origin); // domain
console.log(location.pathname); // path
console.log(location.search); // query string
console.log(location.hash); // hash
In real programming, developers usually avoid manually splitting URLs when built-in properties already provide the exact parts they need.
Mental Model
Think of the browser URL like a label on a folder.
window.location.href = ...is like throwing away the current folder and opening a different one.history.pushState(...)is like changing the label on the folder while keeping the contents currently open.- changing
location.hashis like adding a sticky note to the folder label.
The page reload happens when the browser thinks you are requesting a new document. The History API avoids that by changing the address bar and browser history without making the browser load a new page.
Syntax and Examples
Core syntax
history.pushState(stateObject, "", newUrl);
history.replaceState(stateObject, "", newUrl);
pushStateadds a new history entryreplaceStateupdates the current history entry- the second argument is traditionally unused in modern code, so an empty string is common
Example: change the path without reload
history.pushState({}, "", "/page2.php");
This updates the URL in the address bar to /page2.php on the current domain without reloading the page.
Example: change the query string
history.pushState({}, "", "/products?category=books");
This is useful for filters or search pages.
Example: replace instead of push
history.replaceState({}, "", "/profile?tab=settings");
This changes the current URL but does not add a new browser history entry.
Example: change only the hash
location.hash = "section2";
This usually does not reload the page. It updates only the fragment portion of the URL.
Reading the URL parts
console.log(location.href); // full URL
console.log(location.origin); // https://example.com
console.log(location.pathname); // /page2.php
console.log(location.search); // ?category=books
console.log(location.hash); // #section2
Beginner-friendly example
function showSettingsTab() {
document.body.textContent = "Settings tab is open";
history.pushState({}, "", "/account?tab=settings");
}
showSettingsTab();
What this does
- changes the page content
- updates the URL to match that content
- does not refresh the browser page
Step by Step Execution
Consider this code:
console.log(location.pathname);
history.pushState({}, "", "/dashboard?view=weekly#chart");
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
Step by step
- The first
console.log(location.pathname)prints the current path. history.pushState({}, "", "/dashboard?view=weekly#chart")changes the browser URL without reloading.- The next
console.log(location.pathname)now prints/dashboard. console.log(location.search)prints?view=weekly.console.log(location.hash)prints#chart.
Important detail
The JavaScript environment continues running on the same page. No new document is loaded.
Example trace
If the original URL is:
https://example.com/home
After pushState, the browser shows:
https://example.com/dashboard?view=weekly#chart
But the page was not reloaded. Only the visible URL and history entry changed.
Real World Use Cases
Changing the URL without reloading is common in many types of applications.
Single-page applications
Frameworks like React, Vue, and Angular use this approach for client-side routing.
Example:
/dashboard/dashboard/reports/dashboard/settings
The app changes views without a full page refresh.
Filtered product pages
An online store may update the URL when a user selects filters:
/products?category=shoes&color=black
This makes the filtered view shareable and bookmarkable.
Tabs and panels
A profile page might update the URL when the user opens a tab:
/profile?tab=security
Search interfaces
A search tool might store the current search term or sort order in the URL.
Documentation pages
A docs site may use hashes for section navigation:
/docs/api#authentication
Maps and dashboards
Applications often store zoom level, selected date range, or current panel in the URL so the state can be restored later.
Real Codebase Usage
In real projects, developers usually combine URL updates with application state.
Common pattern: update UI and URL together
function setView(view) {
renderView(view);
history.pushState({ view }, "", `/dashboard?view=${view}`);
}
This keeps the browser URL consistent with what the user sees.
Guard clause for invalid input
function setTab(tab) {
const allowedTabs = ["profile", "security", "billing"];
if (!allowedTabs.includes(tab)) {
return;
}
history.replaceState({ tab }, "", `/account?tab=${tab}`);
}
This prevents invalid URLs from being generated.
Reading URL parameters on load
const params = new URLSearchParams(location.search);
const tab = params.get("tab") || "profile";
renderTab(tab);
This lets the app restore state from the URL.
Handling back and forward navigation
When using pushState, applications often listen for popstate:
window.addEventListener("popstate", (event) => {
console.log("History changed:", event.state);
renderFromUrl();
});
This is important because users expect the browser's back button to work.
When replaceState is preferred
Developers often use replaceState when:
- correcting the current URL
- normalizing query parameters
- updating temporary state that should not create extra history entries
Common Mistakes
1. Using window.location.href when you do not want navigation
Broken example:
window.location.href = "/page2.php";
This reloads the page.
Use this instead:
history.pushState({}, "", "/page2.php");
2. Trying to change to another domain
Broken example:
history.pushState({}, "", "https://othersite.com/page");
This will fail because the History API only works with the same origin.
3. Updating the URL but not updating the UI
Broken example:
history.pushState({}, "", "/settings");
If you change the URL but leave the page content unchanged, users may be confused.
Better:
renderSettingsPage();
history.pushState({}, "", "/settings");
4. Using string splitting when built-in URL properties exist
Less reliable:
const beforeHash = location.href.split("#")[0];
Usually better:
const base = location.origin + location.pathname + location.search;
5. Forgetting back-button behavior
If you use pushState many times but never handle popstate, the user may go back to a URL that does not match the visible UI.
6. Confusing hash changes with path changes
location.hash = "about";
This changes only the fragment. It does not change the actual path like /about.
7. Omitting the leading slash in relative paths
Potentially confusing:
history.pushState({}, "", "page2.php");
Clearer:
history.pushState({}, "", "/page2.php");
Using a leading slash makes it obvious that the path is relative to the site root.
Comparisons
| Approach | Reloads page? | Changes history? | Best use case |
|---|---|---|---|
window.location.href = ... | Yes | Yes | Navigate to a new page or resource |
location.assign(...) | Yes | Yes | Same as href, explicit navigation |
location.replace(...) | Yes | Replaces current entry | Redirect without keeping old page in history |
history.pushState(...) | No | Yes | Update path/query/hash in SPA-style navigation |
history.replaceState(...) | No | Replaces current entry | Update current URL without adding a new history entry |
location.hash = ... | Usually no | Yes | Jump to or store fragment/section state |
pushState vs replaceState
| Method | Adds new history entry? | Back button returns to previous URL? |
|---|---|---|
pushState | Yes | Yes |
replaceState | No | No, current entry is overwritten |
Hash routing vs History API
| Technique | Example URL | Looks cleaner? | Server configuration needed? |
|---|---|---|---|
| Hash routing | /app#settings | No | Usually no |
| History API routing | /app/settings | Yes | Often yes |
The History API usually gives cleaner URLs, but hash-based URLs are simpler in some static setups.
Cheat Sheet
// Reloads page
window.location.href = "/page2.php";
// Change URL without reload
history.pushState({}, "", "/page2.php");
// Change current history entry without reload
history.replaceState({}, "", "/page2.php");
// Change only the hash
location.hash = "section1";
// Read URL parts
location.href // full URL
location.origin // protocol + domain + port
location.pathname // path
location.search // query string
location.hash // fragment
Rules
window.location.href = ...navigates and reloadshistory.pushState()does not reloadhistory.replaceState()does not reload and does not add a new history entry- History API works only on the same origin
- use
popstateto respond to back/forward navigation
Quick tip
To get everything before the hash:
const beforeHash = location.origin + location.pathname + location.search;
Or:
const beforeHash = location.href.split("#")[0];
FAQ
Can I change the URL path without refreshing the page in JavaScript?
Yes. Use history.pushState() or history.replaceState() to update the URL without reloading.
Does window.location.href always reload the page?
Yes. Setting window.location.href triggers navigation, so the browser loads the target URL.
What is the difference between pushState and replaceState?
pushState adds a new history entry. replaceState modifies the current history entry.
Can I modify only the hash without reloading?
Yes. You can set location.hash = "section1". This usually does not reload the page.
Can I change the URL to another domain without reloading?
No. The History API only allows same-origin URLs.
How do I get the URL without the hash part?
You can use:
const beforeHash = location.origin + location.pathname + location.search;
Why does my URL change but my page content stay the same?
Because pushState changes the address bar only. You must also update the UI yourself.
Do browsers support the History API?
Yes, modern browsers support it. It is widely used in single-page applications.
Mini Project
Description
Build a small profile page view switcher that changes the URL when a user selects a tab, without reloading the page. This demonstrates how real applications keep the URL in sync with what the user sees.
Goal
Create a tab-based interface that updates the page content and browser URL using the History API.
Requirements
- Create three tabs: Profile, Security, and Billing.
- When a tab is selected, update the visible content without reloading the page.
- Update the URL query string to reflect the selected tab.
- Restore the correct tab when the page loads from the current URL.
- Handle the browser back and forward buttons correctly.
Keep learning
Related questions
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Apply CSS !important with jQuery .css()
Learn why jQuery .css() cannot set !important and how to use CSSStyleDeclaration.setProperty() to apply inline important styles safely.
CSS ::before and ::after on Input Elements
Learn why CSS ::before and ::after usually do not work on input elements, what replaced elements are, and practical alternatives.