squirrelscan
GitHub

Skip to content: bypassing repeated navigation

Keyboard users tab through the whole navigation on every page without a bypass. squirrel accepts a skip link or landmark structure.

What a bypass mechanism is

Every page on a site repeats the same header and navigation. A mouse user’s eye skips it. A keyboard user presses Tab through all of it, on every page, before reaching the content.

WCAG success criterion 2.4.1 Bypass Blocks, Level A, requires a way past it. A skip link is the classic answer: a link at the very top of the document, hidden until it takes focus, pointing at the main content. Landmarks also satisfy the criterion, because a screen reader user can jump straight to <main>.

What squirrel checks

One check, skip-link, at severity warning. It gathers five signals and grades the combination rather than requiring any one of them.

  • A skip link, matched as a[href^="#main"], a[href^="#content"], a[href="#skip"], or a link with the class skip-link, skip-to-content or skip-nav.
  • Failing that, any a[href^="#"] whose text contains skip, jump to content or go to main.
  • A <main> element or [role="main"].
  • An <h1> or <h2> appearing within the first 2000 characters of the body’s serialized HTML, which is far enough in for a nav bar and not far enough for real content.
  • A <nav> element or [role="navigation"].

The verdict follows from those:

  • Pass with Skip link found when either skip-link signal is present.
  • Pass with Bypass mechanism available via landmarks when a main landmark is present together with a nav landmark or an early heading.
  • Warn with No bypass mechanism for repetitive content otherwise, listing whichever signals were found and suggesting Add skip link or ensure <main> landmark with <nav> landmark.

Every finding carries the list of detected methods, so a pass tells you which mechanism it credited.

How to fix it

<body>
  <a class="skip-link" href="#main">Skip to main content</a>
  <nav aria-label="Primary">...</nav>
  <main id="main" tabindex="-1">...</main>
.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 0;
  top: 0;
}

The link has to be the first focusable element in the document, or the user tabs through part of the header before finding it. Hide it with off-screen positioning rather than display: none, which would take it out of the tab order entirely.

tabindex="-1" on the target matters. Without it some browsers move the scroll position but leave focus where it was, so the next Tab press goes back to the navigation.

Rule IDa11y/skip-link
CategoryAccessibility
ScopePer-page
Severitywarning
Weight4/10

Enable / disable

Disable this rule

[rules]
disable = ["a11y/skip-link"]

Disable all Accessibility rules

[rules]
disable = ["a11y/*"]

Enable only this rule

[rules]
enable = ["a11y/skip-link"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

  • a11y/landmark-one-main: whether the page has exactly one <main>, which clears this rule only alongside a <nav> landmark or an early heading.
  • a11y/landmark-regions: the <nav> landmark that completes the landmark route.
  • a11y/focus-visible: outline: none with no :focus-visible replacement, which is what would hide the skip link.
  • a11y/tabindex: positive values that would move the skip link out of first position.

Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Accessibility section of the report. A pass names which bypass mechanism it credited, so you can see what it found. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close