RatedWithAI

RatedWithAI

Accessibility scanner

GuidesSeptember 19, 2026

Your Skip Link Is Probably There. It Probably Goes Nowhere.

A "skip to content" link is the one accessibility feature built for sighted keyboard users, and the one nobody on the team ever presses. It gets added once, the template changes underneath it, and from then on it looks right in every review while doing nothing at all.

Level A
SC 2.4.1 Bypass Blocks: the lowest bar in WCAG
1 press
What a working skip link turns a whole header of Tab presses into
Every page
How often a keyboard user pays for a header with no way past it

Who the Skip Link Is Actually For

A mouse user jumps straight to the content. A keyboard user starts at the top of the page and presses Tab through every focusable thing in the order the HTML lists it: the logo, the announcement bar, every link in the navigation, the account menu, the search box, the cart. On a typical marketing site or store that is fifteen to forty presses, and they pay it again on every page they open.

Screen reader users have a way around this: shortcut keys that jump by landmark or by heading. People who use a keyboard without a screen reader, because of tremor, RSI, a switch device or simple preference, have none of those shortcuts. For them the skip link is not a nicety; it is the only way past the header.

What WCAG Requires

CriterionLevelWhat it means for a skip link
2.4.1 Bypass BlocksAThere is a mechanism to skip content repeated on multiple pages. A skip link, landmarks and headings are all sufficient techniques.
2.4.7 Focus VisibleAAWhen the skip link has focus, the user can see it. A link that stays off-screen while focused fails here.
2.4.3 Focus OrderAAfter the skip, the next Tab continues from the main content, not from wherever focus was.
2.4.11 Focus Not Obscured (Minimum)AA (WCAG 2.2)The element that receives focus after the skip is not entirely hidden behind a sticky header.

Read strictly, a page with a <main> element meets 2.4.1 without any skip link, and that is why a missing skip link is a review item in our checker rather than a failure. But the sufficient technique that serves every keyboard user is the link, and a page that ships one which does not work has the cost of the feature with none of the benefit.

The Five Ways a Skip Link Breaks Without Anyone Noticing

1. The target does not exist. The link says href="#main-content" and nothing on the page has that id. A redesign renamed the wrapper, or the id was only ever on the home page template. Pressing Enter does nothing and focus stays at the top. This is the most common failure, and it is invisible to anyone who does not press the link.

2. It is hidden the wrong way. display: none, visibility: hidden and the hidden attribute all remove an element from the tab order. A skip link hidden with any of them can never be focused, so it is never shown and never used. It has to be moved off-screen or clipped instead, and brought back on focus.

3. A base URL rewrites it. On a page with <base href="/">, which Angular applications carry by default, a bare #main resolves against the base, not the current page. On any page but the home page, pressing the skip link navigates to the home page.

4. A router swallows the #. Hash-based client routers read everything after the # as a route. #main becomes a request for a route called "main", which usually renders a not-found view or nothing.

5. It works, but the target lands under a sticky header. The page scrolls, focus moves, and the first thing in the main content is now behind a fixed header. The user sees no change, assumes the link failed, and goes back to pressing Tab.

A Skip Link That Works

<body>
  <!-- The first focusable element on the page -->
  <a class="skip-link" href="#main">Skip to content</a>

  <header>...logo, navigation, search...</header>

  <!-- tabindex="-1" so focus really moves here, in every browser -->
  <main id="main" tabindex="-1">
    <h1>...</h1>
  </main>
</body>
.skip-link {
  position: absolute;
  left: 0.5rem;
  top: 0.5rem;
  transform: translateY(-150%);   /* off-screen, still focusable */
  padding: 0.5rem 1rem;
  background: #111;
  color: #fff;
  z-index: 1000;
}
.skip-link:focus {
  transform: none;                /* on screen the moment it is focused */
  outline: 3px solid #fbbf24;
}

/* A sticky header must not cover the target */
html { scroll-padding-top: 5rem; }

/* No visible ring on the target itself after a skip */
main:focus { outline: none; }

The outline is removed only on the main element, which is a region rather than a control and receives focus only programmatically. Removing it on links and buttons is a different matter and is the subject of our focus indicator guide.

In Angular, write the link as href="/current/path#main" or handle the click and call focus() on the target. In a React or Vue app, the plain anchor works unless a hash router is in use; if it is, handle the click and move focus in script instead of relying on the fragment.

How to Test One in Thirty Seconds

  1. Load the page and click the address bar, then press Tab once. A "Skip to content" link should appear at the top of the page. If nothing appears, it is hidden the wrong way, missing, or not first.
  2. Press Enter. The page should scroll so the main content is visible, and nothing should reload.
  3. Press Tab again. Focus should land on the first link or control inside the main content, not in the navigation.
  4. Repeat on an inner page, not just the home page. That is where a missing id and a base-URL rewrite show up.

How to Check Your Own Page

The checker at the top of this article reads the HTML your page serves and counts the Tab presses between the top of the page and its <main>. It reports whether there is a skip link, whether the id it points at exists anywhere on the page, and, past fifteen tab stops with no skip link, flags the header as one a keyboard user has no way past.

The same read finds the two keyboard failures that are counted outright under SC 2.1.1: elements with a click handler that Tab never reaches, and elements with role="button" or a similar role that a keyboard cannot focus. A removed focus outline and a positive tabindex are flagged for review. A skip link target rendered by JavaScript after load is invisible to it, which is why a broken target is review and not a failure.

It is one page. The whole-site scan renders every page in a real browser and names each WCAG 2.1 AA violation by criterion, with the element and the page it is on, and the checker's result hands your domain straight to it.

Frequently Asked Questions

Is a skip link required by WCAG?

Not by name. SC 2.4.1 Bypass Blocks (level A) requires a mechanism to skip blocks of content repeated on every page, such as the header and navigation. A skip link is one sufficient technique; landmarks (a <main> element, a <nav>) and a proper heading structure are others. The catch is who each one serves: landmarks and headings are navigable by screen reader users, who have shortcut keys for them, but a sighted keyboard user with no screen reader has no landmark navigation at all. The skip link is the only mechanism that works for them.

Why does my skip link not work?

Usually one of five things. The id it points at does not exist on the page (the template was renamed, or the id is only on the home page). The link is hidden with display:none or visibility:hidden, which also removes it from the tab order. The page has a <base href> and the link resolves to another URL, which is common in Angular. A client-side router intercepts the # and treats it as a route. Or it works, but the target sits under a sticky header, so the content scrolls behind it and the user sees nothing move.

Does the skip link target need tabindex="-1"?

It is the safe choice. Every current browser moves the sequential focus starting point to a fragment target, so the next Tab lands in the main content even without it. But with tabindex="-1" on the target, focus actually moves there, screen readers announce the new position, and the result is the same in every browser and every framework that manages focus itself. The -1 keeps the target out of the normal tab order, so it costs nothing.

Should a skip link be visible all the time?

It does not have to be. The common and accepted pattern is to keep it off-screen until it receives focus, then show it at the top-left of the page. What it must not be is hidden with display:none, visibility:hidden or the hidden attribute: those take it out of the tab order, so it is never focused and never shown. When it is shown, it needs a visible focus style of its own, or SC 2.4.7 fails on the very first Tab.

How many skip links should a page have?

One, to the main content, is what almost every page needs. A second can make sense on a page with a very long secondary block, such as a skip to search results past a filter panel. More than two starts to become its own block of links to tab through, which is the problem the first one exists to solve.

Press It Once, on an Inner Page

A skip link is judged by whether it moves focus, not by whether it exists. Check it with the tool at the top of this article, then press it yourself on a page that is not the home page.

For the rest of the keyboard path, see the keyboard accessibility guide. The whole-site scan names every WCAG 2.1 AA failure with the element and page it is on. No signup, no card.

Open the keyboard checker on its own page →