Skip to content

Commit b27ca3f

Browse files
heiskrCopilot
andauthored
Fix accessibility: Focus target element on in-page anchor navigation (#60152)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a09d270 commit b27ca3f

2 files changed

Lines changed: 27 additions & 0 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useEffect } from 'react'
2+
3+
// When an in-page anchor link is clicked (e.g. href="#section-id"),
4+
// browsers scroll to the target but may not move keyboard focus to it.
5+
// This component listens for hash changes and programmatically focuses
6+
// the target element so screen reader and keyboard users land at the
7+
// correct position.
8+
export function ClientSideHashFocus() {
9+
useEffect(() => {
10+
const handleHashChange = () => {
11+
const hash = window.location.hash.slice(1)
12+
if (!hash) return
13+
14+
const target = document.getElementById(hash)
15+
if (target) {
16+
target.focus({ preventScroll: true })
17+
}
18+
}
19+
20+
window.addEventListener('hashchange', handleHashChange)
21+
return () => window.removeEventListener('hashchange', handleHashChange)
22+
}, [])
23+
24+
return null
25+
}

src/frame/pages/app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import { useTheme } from '@/color-schemes/components/useTheme'
1919
import { SharedUIContextProvider } from '@/frame/components/context/SharedUIContext'
2020
import { CTAPopoverProvider } from '@/frame/components/context/CTAContext'
21+
import { ClientSideHashFocus } from '@/frame/components/ClientSideHashFocus'
2122
import type { ExtendedRequest } from '@/types'
2223

2324
type MyAppProps = AppProps & {
@@ -146,6 +147,7 @@ const MyApp = ({ Component, pageProps, languagesContext, stagingName }: MyAppPro
146147
<LanguagesContext.Provider value={languagesContext}>
147148
<SharedUIContextProvider>
148149
<CTAPopoverProvider>
150+
<ClientSideHashFocus />
149151
<Component {...pageProps} />
150152
</CTAPopoverProvider>
151153
</SharedUIContextProvider>

0 commit comments

Comments
 (0)