A skip to main content link is a hidden link at the very top of your page that appears on the first press of the Tab key and, when activated, jumps keyboard users past your header and menus straight to the content. It’s the standard fix for the “bypass blocks” flag in accessibility scans, and it takes one line of HTML and a short block of CSS. The code is below — copy it, paste it, then run the 60-second test at the end to confirm your platform didn’t quietly break it.

The link goes in first, immediately after your opening <body> tag, before the header and navigation:

<body>
  <a href="#main-content" class="skip-link">Skip to main content</a>
  <header><!-- logo, nav, search --></header>
  <main id="main-content" tabindex="-1">
    <!-- your page content -->
  </main>
</body>

And the CSS:

.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  transform: translateY(-120%);
  padding: 0.75rem 1.25rem;
  background: #1a1a1a;
  color: #ffffff;
  text-decoration: underline;
  z-index: 9999;
}

.skip-link:focus {
  transform: translateY(0);
}

That’s the whole fix. Mouse users never see it. A keyboard user presses Tab once, the link slides into view, they press Enter, and they’re reading your content instead of tabbing through forty menu items. This slide-on-focus pattern is the same approach CSS-Tricks documents — hidden with a transform, revealed by a :focus rule.

Three details in that snippet do real work, so don’t trim them:

  1. The href and the id match exactly. #main-content goes nowhere unless an element with id="main-content" exists on the page.
  2. tabindex="-1" sits on the target. As accessibility consultant Adrian Roselli notes in the CSS-Tricks discussion, “while the viewport may visually move the target of the skip link into view, that does not mean keyboard focus has moved.” The tabindex="-1" makes the <main> element programmatically focusable so the next Tab press continues from the content, not from the top of the page. (CSS-Tricks)
  3. The link is first in the source order. WebAIM’s skip navigation guidance is to make sure the link is one of the first items keyboard users reach — a skip link buried after the logo and three nav items defeats its own purpose.

Why not just use display:none?

Because display:none kills the link for the exact people it exists to serve. WebAIM is blunt about it: hiding a skip link with CSS display:none or the hidden attribute “will remove the link from keyboard navigation making it inaccessible to all users” (WebAIM: Skip Navigation Links). visibility:hidden breaks it the same way — the browser drops the link from the Tab order entirely, and screen readers drop it from their output.

The correct pattern, per the same WebAIM guidance, is to hide the link visually while keeping it in the document flow — position it off-screen or transform it out of view, “then cause it to be positioned on screen when it receives keyboard focus.” The CSS above does exactly that. If you inherited a site where the skip link exists in the HTML but never appears on Tab, a display:none in the stylesheet is the first thing to check.

What is the “bypass blocks” flag actually asking for?

Your scanner is checking WCAG Success Criterion 2.4.1 Bypass Blocks, which requires that “a mechanism is available to bypass blocks of content that are repeated on multiple web pages.” It’s a Level A criterion — the most basic conformance tier, part of the WCAG 2.1 AA standard US courts and the DOJ reference. (Our plain-language breakdown of 2.4.1 covers the criterion itself; this article is the implementation.)

The intent is simple. A sighted mouse user’s eyes jump straight to your content. A keyboard or screen-reader user has to move through everything in order — header, logo, every menu link — on every single page. W3C’s understanding document puts it this way: the criterion exists “to allow people who navigate sequentially through content more direct access to the primary content of the web page.” (W3C, Understanding 2.4.1)

A skip link isn’t the only sufficient technique. The same W3C document also accepts grouping repeated content with ARIA landmarks or proper heading elements, since screen readers can jump by landmark and heading. But landmarks do nothing for a sighted keyboard user — someone with a motor disability who can see the page but can’t use a mouse. The skip link is the one mechanism that serves everybody, which is why it’s the fix auditors expect to find.

Plenty of sites technically have a skip link — the HTML is right there — and it still fails. In audits, the breakage almost always comes from one of three places:

BreakageWhat the user experiencesThe fix
1. Hidden with display:noneTab does nothing; the link never appears and never receives focusHide it off-screen with position:absolute / transform, reveal with :focus (WebAIM)
2. Missing or renamed target idThe link appears, but Enter does nothing — href="#main-content" points at an id that doesn’t existAdd id="main-content" (plus tabindex="-1") to your <main>; re-check after theme updates and page-builder changes
3. Smooth-scroll hijackThe page glides down visually, but the next Tab press starts from the top again — focus never movedMake the scroll script call .focus() on the target, or drop the effect

The third one deserves a closer look because it’s invisible to a mouse-based spot check. Many themes and plugins intercept every #anchor click to animate the scroll, and in doing so they cancel the browser’s default focus handling. Amber Hinds, CEO of accessibility firm Equalize Digital, describes the result: “the skip link visually appears to scroll down to the content, but is entirely nonfunctional for screen reader and keyboard users.” Her recommended fix is to have the script set tabindex="-1" on the target and call .focus() — or simply turn the effect off, because the animation “is not worth breaking the skip and anchor links on your website.” (The Admin Bar)

One piece of good news on browser support: in-page skip links used to fail outright on mobile screen readers, but per accessibility firm Axess Lab — which documented the iOS and TalkBack bugs in 2018 — browsers and assistive technology had largely resolved those issues by its April 2020 update. (Axess Lab) The tabindex="-1" on the target remains the belt-and-suspenders move that makes the pattern reliable everywhere.

Check before you build: WordPress default themes (the Twenty-* series) and anything tagged accessibility-ready in the theme directory already include one. That tag isn’t decorative — the WordPress accessibility-ready guidelines require that “themes must include an in-page link that helps users navigate directly to content,” that it be visible when keyboard focus lands on it, and that it move focus to the main content area when activated.

If your theme has no skip link, or a broken one:

  1. Classic themes: paste the HTML snippet from above into header.php, immediately after <body ...> (in a child theme, so updates don’t erase it), and add the CSS under Appearance → Customize → Additional CSS. Confirm your content container has the matching id — many themes use id="content" or id="main", and pointing your href at the existing id beats renaming it.
  2. Block themes: WordPress core injects a skip link on block themes, but its script looks for a main element and bails out if none exists — so if yours is missing, the usual cause is a custom template built without a main block. Add one, then run the test below.
  3. Any theme with a smooth-scroll plugin or page builder: test after every change. Builders regenerate markup, and a renamed wrapper id is breakage number 2 in the table above.

The skip link is one item on a longer list for that platform — our WordPress accessibility guide covers the theme and plugin issues that usually ride along with it. On hosted platforms the same logic applies: find whether a skip link exists, and test it. Shopify store owners can start with our rundown of Shopify theme accessibility pitfalls.

The 60-second keyboard verification test

Code pasted, cache cleared. Now prove it works — no tools, just the keyboard:

  1. Load the page fresh and click once in the address bar so focus starts above the page.
  2. Press Tab once. The skip link should appear at the top of the viewport, clearly visible. If nothing appears: breakage 1 — check for display:none.
  3. Read it. It should say what it does — “Skip to main content,” not “Skip” or an icon.
  4. Press Enter. The view should jump past your header to the content. If nothing happens: breakage 2 — the target id is missing or misspelled.
  5. Press Tab again. Focus should land on the first link or button inside your content, not back on your logo or menu. If you’re back at the top: breakage 3 — a script moved the scroll but not the focus.
  6. Press Shift+Tab twice to make sure nothing upstream traps you.

Pass all six and your bypass blocks flag is genuinely fixed — not just quiet. This check is Step 5 of our full 10-minute keyboard test, which is worth running on the rest of the page while your hands are already off the mouse; the deeper background lives in our keyboard navigation guide.

Here’s the honest caveat: a “bypass blocks” flag rarely travels alone. The same scan that caught it usually caught missing focus indicators, unlabeled buttons, or contrast failures — and the automated scan itself only surfaces a fraction of what a manual tester finds. The skip link is the fifteen-minute fix on a list where other items need real remediation work in the markup.

So paste the fix, run the test, and enjoy the win. Then find out what else is on the list: run a free accessibility scan for the machine-readable baseline, and if the results go beyond copy-paste territory, our manual remediation service fixes the underlying code — the skip link, the focus order, and everything between them — so the keyboard test passes on every page, not just this one.