diff --git a/apps/settings/lib/Controller/AppSettingsController.php b/apps/settings/lib/Controller/AppSettingsController.php
index a4addfc5b35604e21ec6d4e6bece2a5a26bcf8cd..d0ed408df0207464049676b6aa7991aedf34674c 100644
--- a/apps/settings/lib/Controller/AppSettingsController.php
+++ b/apps/settings/lib/Controller/AppSettingsController.php
@@ -136,7 +136,7 @@ class AppSettingsController extends Controller {
 		$params['bundles'] = $this->getBundles();
 		$this->navigationManager->setActiveEntry('core_apps');
 
-		$templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params]);
+		$templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params, 'pageTitle' => $this->l10n->t('Apps')]);
 		$policy = new ContentSecurityPolicy();
 		$policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
 		$templateResponse->setContentSecurityPolicy($policy);
diff --git a/apps/settings/lib/Controller/UsersController.php b/apps/settings/lib/Controller/UsersController.php
index 217abf0e156be9d97a007163c3179cbc1c7ab992..89a850c19809afcc758de0044c151c976970a08b 100644
--- a/apps/settings/lib/Controller/UsersController.php
+++ b/apps/settings/lib/Controller/UsersController.php
@@ -277,7 +277,7 @@ class UsersController extends Controller {
 		$serverData['newUserRequireEmail'] = $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes';
 		$serverData['newUserSendEmail'] = $this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes';
 
-		return new TemplateResponse('settings', 'settings-vue', ['serverData' => $serverData]);
+		return new TemplateResponse('settings', 'settings-vue', ['serverData' => $serverData, 'pageTitle' => $this->l10n->t('Users')]);
 	}
 
 	/**
diff --git a/apps/settings/src/router.js b/apps/settings/src/router.js
index 863bd49c32db17bee0a2ad544c2656330db3c933..cf842475c5da6a6174ba3ca31ec0b8aa6548087b 100644
--- a/apps/settings/src/router.js
+++ b/apps/settings/src/router.js
@@ -27,6 +27,7 @@ import Router from 'vue-router'
 import { generateUrl } from '@nextcloud/router'
 import { APPS_SECTION_ENUM } from './constants/AppsConstants.js'
 import store from './store/index.js'
+import { setPageHeading } from '../../../core/src/OCP/accessibility.js'
 
 // Dynamic loading
 const Users = () => import(/* webpackChunkName: 'settings-users' */'./views/Users')
@@ -126,6 +127,7 @@ router.afterEach(async (to) => {
 	const metaTitle = await to.meta.title?.(to)
 	if (metaTitle) {
 		document.title = `${metaTitle} - ${baseTitle}`
+		setPageHeading(metaTitle)
 	} else {
 		document.title = baseTitle
 	}
diff --git a/apps/settings/tests/Controller/AppSettingsControllerTest.php b/apps/settings/tests/Controller/AppSettingsControllerTest.php
index 28d77dc3696a3e2d9ebcef3ca4217af19aa16759..8d0dae223d33e264c5e2c965734534fafd3d941d 100644
--- a/apps/settings/tests/Controller/AppSettingsControllerTest.php
+++ b/apps/settings/tests/Controller/AppSettingsControllerTest.php
@@ -209,7 +209,8 @@ class AppSettingsControllerTest extends TestCase {
 					'appstoreEnabled' => true,
 					'bundles' => [],
 					'developerDocumentation' => ''
-				]
+				],
+				'pageTitle' => 'Apps'
 			],
 			'user');
 		$expected->setContentSecurityPolicy($policy);
@@ -243,7 +244,8 @@ class AppSettingsControllerTest extends TestCase {
 					'appstoreEnabled' => false,
 					'bundles' => [],
 					'developerDocumentation' => ''
-				]
+				],
+				'pageTitle' => 'Apps'
 			],
 			'user');
 		$expected->setContentSecurityPolicy($policy);
diff --git a/core/src/OCP/accessibility.js b/core/src/OCP/accessibility.js
index 3839509228fe32b0f74128c8145e41352187a4e5..72bd8a7058283e3c0c35ab8384aea83670fa195b 100644
--- a/core/src/OCP/accessibility.js
+++ b/core/src/OCP/accessibility.js
@@ -22,6 +22,17 @@
 
 import { loadState } from '@nextcloud/initial-state'
 
+/**
+ * Set the page heading
+ *
+ * @param {string} heading page title from the history api
+ */
+export function setPageHeading(heading) {
+	const headingEl = document.getElementById('page-heading-level-1')
+	if (headingEl) {
+		headingEl.textContent = heading
+	}
+}
 export default {
 	/**
 	 * @return {boolean} Whether the user opted-out of shortcuts so that they should not be registered
@@ -29,4 +40,5 @@ export default {
 	disableKeyboardShortcuts() {
 		return loadState('theming', 'shortcutsDisabled', false)
 	},
+	setPageHeading,
 }
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index dc38f642ca43a51cfcf8e0de81ea8a4b59873988..7c2625bbaaf0beabd69c56dd513607a9bb0434a6 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -57,6 +57,9 @@ p($theme->getTitle());
 		</div>
 
 		<header role="banner" id="header">
+			<h1 class="hidden-visually" id="page-heading-level-1">
+				<?php p(!empty($_['pageTitle'])?$_['pageTitle']:$theme->getName()); ?>
+			</h1>
 			<div class="header-left">
 				<a href="<?php print_unescaped($_['logoUrl'] ?: link_to('', 'index.php')); ?>"
 					id="nextcloud">
@@ -89,9 +92,6 @@ p($theme->getTitle());
 		</form>
 
 		<main id="content" class="app-<?php p($_['appid']) ?>">
-			<h1 class="hidden-visually">
-				<?php p($l->t('%s\'s homepage', [$theme->getName()])); ?>
-			</h1>
 			<?php print_unescaped($_['content']); ?>
 		</main>
 		<div id="profiler-toolbar"></div>
diff --git a/dist/core-main.js b/dist/core-main.js
index c1ced7eb8e6a0182885de4fb68262903a98fcd91..1b6d45cfc8180bdb5a4113c0cf5f703700451650 100644
Binary files a/dist/core-main.js and b/dist/core-main.js differ
diff --git a/dist/core-main.js.map b/dist/core-main.js.map
index 064fd27aa5c22338a2274be525cca4cd96c1a40b..620997356772fa43a9be52b47b719ad4d02685cb 100644
Binary files a/dist/core-main.js.map and b/dist/core-main.js.map differ
diff --git a/dist/settings-vue-settings-apps-users-management.js b/dist/settings-vue-settings-apps-users-management.js
index 73aaf07684e66ced3809d3989ad4d185ef324175..deb11bbebf116b874ace268661413c55a6b27df4 100644
Binary files a/dist/settings-vue-settings-apps-users-management.js and b/dist/settings-vue-settings-apps-users-management.js differ
diff --git a/dist/settings-vue-settings-apps-users-management.js.LICENSE.txt b/dist/settings-vue-settings-apps-users-management.js.LICENSE.txt
index e68f74c1a692b20d4d0f3780895b3737370d0e9d..ed9670c8ea31b7fe10504c3a839ec02a0ef49860 100644
Binary files a/dist/settings-vue-settings-apps-users-management.js.LICENSE.txt and b/dist/settings-vue-settings-apps-users-management.js.LICENSE.txt differ
diff --git a/dist/settings-vue-settings-apps-users-management.js.map b/dist/settings-vue-settings-apps-users-management.js.map
index c7941ffd1dff735fa06a1d9124051fb711c69104..159e1e04031228809a66c97645aa53e5bd190f93 100644
Binary files a/dist/settings-vue-settings-apps-users-management.js.map and b/dist/settings-vue-settings-apps-users-management.js.map differ