usability.cat
Issue Wiki

Missing Skip-to-Content Link

Your keyboard users are forced to Tab through your entire nav bar on every single page. Here's the 2-minute fix.

What is this?

You know that "Skip Intro" button on Netflix? A skip link does the same thing for your website. It is a hidden link at the very top of the page that lets keyboard and screen reader users jump straight to the main content, instead of tabbing through your logo, nav links, social icons, and whatever else lives in your header — on every. single. page.

Why it matters

  • For your visitors: Imagine pressing Tab 47 times just to get past the navigation. Every time you load a new page, you start over. That is the reality for anyone who cannot use a mouse — people with motor disabilities, power keyboard users, and screen reader users. It is exhausting and it makes your site feel hostile.
  • For your business: If someone has to fight your interface to reach your content, they leave. Keyboard users include people with temporary injuries, RSI, or anyone using assistive technology. Losing them means losing customers.
  • The standard: WCAG 2.4.1 (the accessibility guidelines that define how websites should work for everyone) requires "a mechanism to bypass blocks of content that are repeated on multiple pages." A skip link is the simplest way to comply.
With a skip link
<body>
  <a href="#main-content" class="skip-link">
    Skip to content
  </a>
  <nav><!-- your navigation --></nav>
  <main id="main-content">
    <h1>Your actual content</h1>
  </main>
</body>
No skip link
<body>
  <nav><!-- 20+ links to tab through --></nav>
  <main>
    <h1>Your actual content</h1>
  </main>
</body>

How to fix it

React / Next.js

Add the skip link as the very first element inside your layout. It stays hidden until a keyboard user presses Tab, then it appears.

// src/app/layout.tsx (or your root layout)
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {/* Skip link — must be the FIRST focusable element */}
        <a
          href="#main-content"
          className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:rounded focus:bg-white focus:px-4 focus:py-2 focus:text-black focus:shadow-lg"
        >
          Skip to content
        </a>
        <header>{/* your nav */}</header>
        <main id="main-content">{children}</main>
      </body>
    </html>
  );
}

The sr-only class hides the link visually but keeps it in the tab order. When focused, focus:not-sr-only makes it visible. Your keyboard users see it; everyone else never notices.

Plain HTML

<!-- Add this right after the opening <body> tag -->
<a href="#main-content" class="skip-link">Skip to content</a>

<!-- Your navigation goes here -->
<nav>...</nav>

<!-- Add the matching id to your main content area -->
<main id="main-content">
  <h1>Welcome</h1>
</main>

<style>
  .skip-link {
    position: absolute;
    top: -40px;
    left: 0;
    padding: 8px 16px;
    background: #000;
    color: #fff;
    z-index: 100;
    transition: top 0.2s;
  }
  .skip-link:focus {
    top: 0;
  }
</style>
High impactaccessibility~2 paws

This is one of the easiest wins in accessibility. Two minutes of work, permanent paw boost. The cat is not impressed when this is missing.

How the cat scores this

The cat looks for an anchor link that targets the main content area (<main> or an element with a role of main) and appears as one of the first focusable elements in the page. If no skip link exists, or if it points to a non-existent ID, the cat flags it. The cat also checks that the link becomes visible on focus — a skip link that is permanently hidden with display: none does not count.

Further reading

On this page