diff --git a/.changeset/selfish-avocados-develop.md b/.changeset/selfish-avocados-develop.md
new file mode 100644
index 000000000000..b7cc85efd54f
--- /dev/null
+++ b/.changeset/selfish-avocados-develop.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+Announce page changes
diff --git a/packages/kit/src/core/create_app.js b/packages/kit/src/core/create_app.js
index 010715311393..556efaae05d7 100644
--- a/packages/kit/src/core/create_app.js
+++ b/packages/kit/src/core/create_app.js
@@ -133,7 +133,7 @@ function generate_app(manifest_data) {
return trim(`
@@ -162,5 +178,25 @@ function generate_app(manifest_data) {
${pyramid.replace(/\n/g, '\n\t\t\t\t')}
{/if}
+
+ {#if mounted}
+
+ {#if navigated}
+ Navigated to {title}
+ {/if}
+
+ {/if}
+
+
`);
}
diff --git a/test/apps/basics/src/routes/accessibility/__tests__.js b/test/apps/basics/src/routes/accessibility/__tests__.js
index 0883023804df..80007435df2b 100644
--- a/test/apps/basics/src/routes/accessibility/__tests__.js
+++ b/test/apps/basics/src/routes/accessibility/__tests__.js
@@ -18,4 +18,22 @@ export default function (test) {
assert.equal(await evaluate(() => document.activeElement.nodeName), 'A');
assert.equal(await evaluate(() => document.activeElement.textContent), 'a');
});
+
+ test('announces client-side navigation', async ({ visit, click, contains, html, js }) => {
+ await visit('/accessibility/a');
+
+ const has_live_region = await contains('aria-live');
+
+ if (js) {
+ assert.ok(has_live_region);
+
+ // live region should exist, but be empty
+ assert.equal(await html('[aria-live]'), '');
+
+ await click('[href="/accessibility/b"]');
+ assert.equal(await html('[aria-live]'), 'Navigated to b'); // TODO i18n
+ } else {
+ assert.ok(!has_live_region);
+ }
+ });
}