HTML onhashchange Attribute

Beginner
⏱️ 6 min read
📚 Updated: Jun 2026
🎯 3 Examples
Events & Handlers

Introduction

The onhashchange handler runs JavaScript when the URL hash (fragment identifier) changes — the part after # in the address bar. Unlike onfocus on form fields, this is a window-level event: you assign window.onhashchange or use window.addEventListener("hashchange", …). It fires when users click in-page anchor links, use back/forward on hash URLs, or when script sets location.hash. Common uses include simple tab panels, lightweight “single-page” views, and deep links to a section — all without reloading the page.

What You’ll Learn

01

Window handler

Not on inputs.

02

hashchange

# fragment.

03

location.hash

Read the hash.

04

SPA-style UI

Swap content.

05

addEventListener

Preferred way.

06

vs popstate

History API.

Purpose of onhashchange Attribute

The primary purpose of onhashchange is to react when the hash portion of the URL changes so your page can update content without a full reload. For example, clicking <a href="#about"> changes the hash to #about; your handler reads location.hash and shows the About panel.

Hash routing is a beginner-friendly pattern for small apps and tutorials. Larger production apps often use the History API (pushState + popstate) instead, but understanding hashchange is still valuable — many sites and docs use hash links.

💡
Run once on load

hashchange does not fire on initial page load. Call your render function once after attaching the handler so the first URL (e.g. #home) displays correctly.

📝 Syntax

Assign the handler on window — the event target for hash changes:

onhashchange.html
<script>
  function handleHashChange() {
    const hash = location.hash.slice(1) || "home";
    document.getElementById("content").textContent = "View: " + hash;
  }

  window.onhashchange = handleHashChange;
  handleHashChange(); // initial render
</script>

Syntax Rules

  • Target is window, not individual HTML elements.
  • Value is JavaScript executed when the hashchange event fires.
  • Triggered by anchor clicks, location.hash = "#foo", and browser back/forward on hash URLs.
  • Does not fire when only the query string (?id=1) or path changes without a hash change.
  • JavaScript: window.onhashchange = function() { … }.
  • Modern alternative: window.addEventListener("hashchange", handler).

💎 Values

The onhashchange property accepts a function (or function reference):

  • window.onhashchange = handleHashChange — Named function reference.
  • window.onhashchange = function() { … } — Inline anonymous function.
  • Preferred: window.addEventListener("hashchange", handler).
onhashchange-js.html
window.addEventListener("hashchange", () => {
  const section = location.hash.slice(1) || "home";
  console.log("Hash is now:", section);
  renderSection(section);
});

// Also run on first load:
renderSection(location.hash.slice(1) || "home");

⚡ Quick Reference

Actionhashchange fires?Notes
Click <a href="#about">YesClassic in-page nav
location.hash = "#settings"YesProgrammatic change
Browser Back on hash historyYesHistory entry with different hash
First page load with #homeNoCall render manually once
Change query only (?page=2)NoHash unchanged
history.pushState() (path only)NoUse popstate instead

Applicable Elements

TargetSupported?Notes
windowYesPrimary and correct target
document / window.addEventListenerYesRecommended registration
<input>, <button>NoNot a form/element event
<body onhashchange>AvoidUse window in script instead

hashchange vs popstate vs onfocus

Handler / eventWhen it firesTypical use
hashchangelocation.hash changesSimple tabs, hash routing
popstateHistory navigation (pushState entries)Modern SPA routing
onfocusElement gains focusForm fields, keyboard UX

Examples Gallery

Swap content from the URL hash, register with addEventListener, and handle the initial load.

👀 Live Preview

Click a tab — the hash updates and content changes without reload:

Loading view…

Current hash: (none)

Example — Dynamic content from hash

Update a content region whenever the URL fragment changes:

hash-content.html
<h1>Dynamic Content Based on Hash</h1>
<nav>
  <a href="#home">Home</a>
  <a href="#about">About</a>
</nav>
<div id="content"></div>

<script>
  function handleHashChange() {
    var hash = location.hash.substring(1) || "home";
    document.getElementById("content").textContent =
      "Content based on hash: " + hash;
  }
  window.onhashchange = handleHashChange;
  handleHashChange();
</script>
Try It Yourself

How It Works

The browser fires hashchange on window when the fragment changes. Reading location.hash tells you which “view” to show.

Dynamic Values with JavaScript

Attach the handler with addEventListener:

dynamic-onhashchange.html
<script>
  window.addEventListener("hashchange", function () {
    console.log("Hash changed to:", location.hash);
  });

  // Or property form:
  window.onhashchange = function () { /* … */ };
</script>
Try It Yourself

How It Works

Register once at page load. Any hash change — from links or script — triggers the same callback.

Example — Handle initial hash on load

Because hashchange does not fire on first load, call your render function immediately:

initial-hash.html
function renderFromHash() {
  const id = location.hash.slice(1) || "home";
  document.querySelectorAll("[data-view]").forEach(el => {
    el.hidden = el.dataset.view !== id;
  });
}

window.addEventListener("hashchange", renderFromHash);
renderFromHash(); // run once for URL like page.html#about
Try It Yourself

How It Works

Share one function between the event listener and the initial call — keeps first paint and later navigation consistent.

♿ Accessibility

  • Update the document title — When hash routing changes the main view, update document.title so screen reader users know the page context changed.
  • Move focus intentionally — After swapping content, move focus to the new heading or main region with tabindex="-1" if appropriate.
  • Don’t rely on hash alone — Critical state should still be available without JavaScript; hash links should map to real content.
  • Use semantic headings — Each “view” should have a proper <h1> or <h2> for structure.
  • Announce changes — Consider aria-live regions when dynamic panels update.

🧠 How onhashchange Works

1

Hash in URL changes

Link click or script.

#fragment
2

Browser skips reload

Same document stays.

SPA
3

hashchange fires

onhashchange runs.

Event
=

Dynamic in-page UI

Tabs, panels, deep links.

Browser Support

The hashchange event and window.onhashchange are supported in all modern browsers — Chrome, Firefox, Safari, and Edge. Internet Explorer 8+ also supports it.

DOM Events · Fully supported

Universal hashchange support

All major browsers fire the event on the window object when the URL fragment changes.

98% Browser support
Google Chrome Fully supported
Full support
Mozilla Firefox Fully supported
Full support
Apple Safari Fully supported
Full support
Microsoft Edge Fully supported
Full support
Internet Explorer IE 8+ supported
Full support
Opera Fully supported
Full support
onhashchange / hashchange event 98% supported

Bottom line: Safe for hash-based navigation in all browsers you are likely to support today.

💡 Best Practices

✅ Do

  • Call your render function once on initial page load
  • Use addEventListener("hashchange", …) in production code
  • Keep hash values short and URL-safe (e.g. #settings)
  • Update document.title when the main view changes
  • Test back/forward buttons with hash history

❌ Don’t

  • Attach onhashchange to form elements — use window
  • Assume hashchange fires on first load
  • Store sensitive data only in the hash (visible in URL and history)
  • Rely on hash routing alone for large apps — consider History API
  • Forget accessibility when swapping visible panels

Conclusion

The onhashchange handler lets your page respond when the URL fragment changes — a simple way to build tabs, lightweight routing, and shareable deep links without reloading.

Register on window, read location.hash, run your render logic once on load, and prefer addEventListener for maintainable code.

Key Takeaways

Knowledge Unlocked

Five truths every developer should know about onhashchange

Bookmark these before building hash-based navigation.

5
Core concepts
🔗 02

# hash

Fragment ID.

URL
🚀 03

No reload

Same document.

SPA
📝 04

Initial load

Render manually.

Gotcha
🔄 05

popstate

History API.

Compare

❓ Frequently Asked Questions

It runs JavaScript when the URL hash (#fragment) changes — on the window object, not on form elements.
Use window.onhashchange or window.addEventListener("hashchange", handler).
No. Call your render function once after attaching the listener to handle the initial hash.
hashchange tracks location.hash. popstate tracks History API navigation from pushState / replaceState.
addEventListener("hashchange", handler) is preferred for production. window.onhashchange is fine for learning.
Yes in all modern browsers; Internet Explorer 8+ as well.

Master hash-based navigation

Practice the onhashchange handler with tab-style examples in the Try It editor.

Try onhashchange demo →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful