Skip to content

WEB-UX-004 — Move focus to main content after SPA path navigation - #658

Merged
daliu merged 1 commit into
mainfrom
codex/issue-657-spa-route-focus
Aug 14, 2026
Merged

WEB-UX-004 — Move focus to main content after SPA path navigation#658
daliu merged 1 commit into
mainfrom
codex/issue-657-spa-route-focus

Conversation

@daliu

@daliu daliu commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Outcome

Move keyboard focus into the destination main content after a committed client-side pathname transition, unless the destination or user has already established newer connected focus. Preserve initial-load focus, same-path URL changes, scrolling, released mobile-menu behavior, and the existing skip-link target.

Officer impact: No officer duty or backend workflow changes. After publication, signed-out and signed-in keyboard users will enter the new page content after SPA path navigation instead of remaining in persistent or hidden navigation.

Officer documentation: docs/officers/PUBLISH_AND_CHECK.md

Deployment evidence: Exact-head CI run 31778085226 passed all five jobs. Netlify deploy-preview 6a7ebc3388b62b0008ee950f is ready at exact head a411cb4e, review #658, published_at:null, with no Netlify Functions or edge functions; header and redirect checks passed and Pages-changed skipped as expected. Its root and /shop return HTTPS 200 with X-Robots-Tag:noindex. Signed-out preview review passed at 1280×900 and 390×844: initial load left body focused with no cue; navigation focused exact main#main-content at scroll (0,0); the fixed cue was fully inset at top 94px and 6px on the other sides, pointer-inert, z98 below navigation z99, and caused no horizontal overflow; the phone menu closed to hide__nav. Website publication and runmprc.com verification remain pending. No Firebase, outside-provider, account/sign-in, production-data, directory-availability, or connected-backend change is included.

Exact candidate

  • head: a411cb4ebcfb4f1f05b3883721aa55f3d72bc701
  • tree: eac1fe8b86f0e871d2fc41e5338dceace38a04ec
  • sole parent/base: 3265a55cb92df1ebb5401f2647ff81e4ca3af0b8
  • exact six paths, +731/-6
  • runtime SHA-256: ea9c32ae30493a11e42206327055cbd0001c21b0e378ed09caa6e2a55bead576
  • test SHA-256: d50ff54aab64b1bdf73bea756946238df80453d11bfc7ba540cecf4e8557e5ef
  • docs SHA-256: 39166cdd26c2de8e1c0ef5b483058dab54da463c2ed2f2265e25b7df290c5e96
  • combined diff SHA-256: fcccd40bfb210bc10e2a6ee31f03b2c6b5d021f5a441280aa7dc2424e25e7c36

Behavior

  • Keeps the existing pathname-keyed top-of-page scroll behavior.
  • Captures the exact main target and outgoing focus origin in layout, then schedules one cancelable passive-effect animation-frame settlement.
  • Consumes before checks, validates exact target identity, and fences redirects, superseded work, replacement targets, and unmount.
  • Focuses main#main-content once with preventScroll only from the unchanged origin or lost/disconnected focus.
  • Preserves main descendants and any different connected destination/user focus.
  • Adds tabIndex={-1} without adding main to ordinary Tab order.
  • Adds one scoped, fixed, pointer-inert two-tone cue fully inside the viewport below navigation; the released global WEB-UX-002 — Restore visible keyboard focus across the site #291 rule stays byte-identical and WEB-UX-003 — Make mobile navigation state explicit and deterministic #490 mobile navigation source stays unchanged.

Trustworthy RED

  • Unchanged route runtime: test-only diff ea14897d70e85f27f2a5c80d4422a4faad31ddaa4055fee99672d2252829f733; 1 failed / 362 skipped because persistent navigation retained focus.
  • Pre-cue CSS: test-only diff 5d5f37a666ee61f4ef9b3481f345ed9371002a9635a5aa2b84518fb059727102; the focused cue test failed because the scoped rule was absent.

Scope and safety

Only these paths change:

  • src/components/ScrollToTop.jsx
  • src/App.jsx
  • src/App.test.jsx
  • src/index.css
  • src/headerClearance.test.js
  • docs/officers/PUBLISH_AND_CHECK.md

Directory availability remains literal false. This adds no route, request, retry, analytics event, log, storage, authentication, membership, photo/search, Firebase, provider, or production-data behavior. Production publication and exact live verification will be recorded separately from merge and preview evidence.

Hosted evidence

  • CI: run 31778085226, all five jobs successful at exact head
  • Deploy Preview: 6a7ebc3388b62b0008ee950f, ready, exact head/review/branch, unpublished
  • Preview assets: static/js/main.9cf94ee6.js contains the preventScroll handoff; static/css/main.31f728fa.css contains the scoped fixed cue
  • Preview visual evidence: signed out at 1280×900 and 390×844; exact main focus, bounded visible cue, phone-menu close, scroll preservation, and no horizontal overflow verified
  • Provider containment: no Netlify Functions or edge functions; no Firebase/provider/account/data action

Closes #657

@netlify

netlify Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy Preview for luminous-fox-7c393f ready!

Name Link
🔨 Latest commit a411cb4
🔍 Latest deploy log https://app.netlify.com/projects/luminous-fox-7c393f/deploys/6a7ebc3388b62b0008ee950f
😎 Deploy Preview https://deploy-preview-658--luminous-fox-7c393f.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@daliu
daliu merged commit 9588074 into main Aug 14, 2026
9 checks passed
@daliu
daliu deleted the codex/issue-657-spa-route-focus branch August 14, 2026 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WEB-UX-004 — Move focus to main content after SPA path navigation

1 participant