Skip to content

Skip links need a target that exists

  • Rule: axe/skip-link
  • Checks: The skip-link target should exist and be focusable
  • WCAG: none; a best practice, not a WCAG success criterion
  • Fix class: mechanical: A fix needs no authored text or visual decision.
  • People who use a keyboard or a switch device instead of a mouse.
  • People who use a screen reader or a braille display, most of them blind.
Section titled “The skip link’s href names an id that is not on the page”

Point the link at the id of the element where the main content starts, usually <main>, spelled with the same case. Give the target tabindex="-1" if it is not focusable, so focus moves with the scroll.

<a class="skip-link" href="#main">Skip to main content</a>
<main id="main" tabindex="-1">
<h1>Order history</h1>
</main>
Section titled “The target exists but is hidden when the link is used”

axe asks for review. Show the target before focus moves to it: an element hidden with display: none or the hidden attribute cannot take focus.

Section titled “Hiding the skip link with display: none or visibility: hidden”

It can then never take focus, so no one can use it. Hide it with a class that moves or clips it, and show it on :focus.

The part of the fix that differs in React, in its syntax. The rest of the guidance holds.

Section titled “The skip link targets an id inside route content that is not always mounted”

Put the id on the <main> of the layout component every route renders inside, so the target exists on every page, even while route content loads.

function Layout({ children }) {
return (
<>
<a className="skip-link" href="#main">
Skip to main content
</a>
<SiteHeader />
<main id="main" tabIndex={-1}>
{children}
</main>
</>
);
}

The app uses hash-based routing, so href="#main" changes the route

Section titled “The app uses hash-based routing, so href="#main" changes the route”

Keep the href, but handle the click: prevent the default and move focus to the target yourself, so the router never sees the hash.

Scrolling the target into view in the click handler without focusing it

Section titled “Scrolling the target into view in the click handler without focusing it”

The page moves, but focus stays on the skip link, so the next Tab still goes through the navigation.

axe-core’s documentation of the rule

CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.