No skip link: keyboard users cannot bypass TopNav (WCAG 2.4.1, level A) #223
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
TopNavrenders at the top of every authenticated route, so a keyboard or screen-reader user tabs through the whole navigation block again on each page before reaching the content. There is no way to bypass it.That is WCAG 2.2 success criterion 2.4.1 Bypass Blocks, level A, and therefore also EN 301 549 clause 9.2.4.1, which applies to this project.
Current state, measured on
main(961d3d5)TopNavInbox,ReadingList,Settings,ConceptBerichten,Notities,UitgaandePost,Voorwaarden,Welkom)<main>elements infrontend/src<nav>elementsrole="main"/role="navigation"The 29 grep hits for "skip" in
frontend/srcare allskipped,skipAuthRedirectand similar - none is a skip link.Note that
Welkom.vueusesnldd-page, which supplies a<main>from its own shadow root. The other seven routes render a plain<div class="page-shell">.Proposed fix
nldd-skip-linkships in 0.8.77 (export./skip-link) and needs no app shell. Read its contract before implementing: it wraps the skippable content in its default slot, and withouthrefit moves focus to itsnextElementSibling, putting atabindex="-1"on that element itself. So the shape is:Two things worth knowing up front:
href. Thehrefvariant renders a real<a>with a fragment, and the router'sscrollBehaviorignoresto.hash, which makes the page jump to the top instead.<main>must be the next sibling. OnInboxthat meansSkipTourButtonandRetentionIntroBannermove inside<main>.Also add
'nldd-skip-link'toNLDD_TAGSinfrontend/src/test-setup.ts, or Vue logs an unknown-element warning in every test that renders a route.Adding
<main>on its own is not a separate success criterion - landmarks are a technique (ARIA11) for 1.3.1 and 2.4.1, not a criterion of their own. The citable failure here is 2.4.1.Out of scope, but related
jest-axeand@axe-core/cliare declared infrontend/package.jsonbut are never invoked - not by an npm script and not by CI. They are a nominal safety net rather than a real one, which is worse than having none, because it reads as covered. Being removed separately; if automated a11y checking is wanted later it should be wired up deliberately rather than left as a dependency that looks like it runs.