diff --git a/.changeset/angry-peaches-beam.md b/.changeset/angry-peaches-beam.md
new file mode 100644
index 000000000000..8d7a8fd61546
--- /dev/null
+++ b/.changeset/angry-peaches-beam.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+fix: correct navigation history with hash router and ensure load functions are rerun on user changes to URL hash
diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js
index 16cecc7fe092..042ea2b39ddf 100644
--- a/packages/kit/src/runtime/client/client.js
+++ b/packages/kit/src/runtime/client/client.js
@@ -2432,6 +2432,12 @@ function _start_router() {
if (!hash_navigating) {
const url = new URL(location.href);
update_url(url);
+
+ // if the user edits the hash via the browser URL bar, trigger a full-page
+ // reload to align with pathname router behavior
+ if (app.hash) {
+ location.reload();
+ }
}
}
});
@@ -2450,13 +2456,6 @@ function _start_router() {
'',
location.href
);
- } else if (app.hash) {
- // If the user edits the hash via the browser URL bar, it
- // (surprisingly!) mutates `current.url`, allowing us to
- // detect it and trigger a navigation
- if (current.url.hash === location.hash) {
- void navigate({ type: 'goto', url: decode_hash(current.url) });
- }
}
});
diff --git a/packages/kit/test/apps/hash-based-routing/src/routes/+layout.svelte b/packages/kit/test/apps/hash-based-routing/src/routes/+layout.svelte
index 5ac801199106..76cae24dfaf8 100644
--- a/packages/kit/test/apps/hash-based-routing/src/routes/+layout.svelte
+++ b/packages/kit/test/apps/hash-based-routing/src/routes/+layout.svelte
@@ -9,6 +9,7 @@
/
/#/a
+/#/b
/#/a#b
/#/b/123
/#/b/456
diff --git a/packages/kit/test/apps/hash-based-routing/test/test.js b/packages/kit/test/apps/hash-based-routing/test/test.js
index 12589824e332..b9ab54dd1249 100644
--- a/packages/kit/test/apps/hash-based-routing/test/test.js
+++ b/packages/kit/test/apps/hash-based-routing/test/test.js
@@ -99,4 +99,20 @@ test.describe('hash based navigation', () => {
const url = new URL(page.url());
expect(url.hash).toBe('#/anchor#test');
});
+
+ test('navigation history works', async ({ page }) => {
+ await page.goto('/');
+
+ await page.locator('a[href="/#/a"]').click();
+ await page.waitForURL('/#/a');
+
+ await page.locator('a[href="/#/b"]').click();
+ await page.waitForURL('/#/b');
+
+ await page.goBack();
+ expect(page.locator('p')).toHaveText('a');
+
+ await page.goForward();
+ expect(page.locator('p')).toHaveText('b');
+ });
});