Frontend

How to Add Skip Links in React (WCAG 2.4.1 Done Right)

May 19, 20265 min read

Skip links satisfy WCAG 2.4.1 (Bypass Blocks) — they let keyboard and screen-reader users skip past repeated navigation to the main content. In a React app, the implementation has two specific gotchas: focus management on client-side route changes, and visibility on focus.

The basic skip link pattern

The HTML pattern is simple:

<a href="#main-content" className="skip-link">Skip to main content</a>
...
<main id="main-content">
  ...
</main>

The CSS hides it visually but reveals it on focus:

.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #1142ff;
  color: white;
  padding: 8px 16px;
  z-index: 100;
  text-decoration: none;
}
.skip-link:focus {
  top: 0;
}

The React gotcha #1: SPA routing breaks the anchor

When you click a regular anchor link in React Router or Next.js, the framework intercepts the click and does client-side routing instead of letting the browser handle #hash navigation. The skip link breaks silently.

Fix: add a click handler that manually moves focus to the target.

function SkipLink() {
  const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
    e.preventDefault()
    const main = document.getElementById('main-content')
    if (main) {
      main.setAttribute('tabindex', '-1')
      main.focus()
      main.scrollIntoView()
    }
  }
  return (
    <a href="#main-content" onClick={handleClick} className="skip-link">
      Skip to main content
    </a>
  )
}

The React gotcha #2: focus restored on route change

When the user navigates client-side, focus returns to the top of the page (or stays wherever it was). The next Tab will hit the skip link again — good. But if your app moves focus elsewhere on route change (e.g. focus the new page's H1), make sure the skip link is still the first Tab stop.

The skip link must be the first focusable element

Audit your root layout. Anything before the skip link (sticky banner, cookie consent, header) must either not be focusable OR also offer keyboard-bypass.

Multiple skip links

Beyond "skip to main content", consider:

  • Skip to navigation (jumps to <nav>)
  • Skip to search (if you have a sticky search)
  • Skip to footer

Multiple skip links go in the same hidden-until-focus container, in tab order.

Next.js App Router specifics

Place the skip link in your root layout, outside the page content slot. Use a client component since it needs an onClick handler. Server Components emit static HTML, which is fine for the anchor itself, but the click handler requires "use client".

How to verify

  1. Open your page in a fresh tab
  2. Press Tab — the skip link should appear at the top of the viewport
  3. Press Enter — focus should move to the main content area
  4. Press Tab again — focus should move to the first interactive element inside main, not back to the navigation

Run an AccessProof scan or use our free WCAG scanner to confirm WCAG 2.4.1 passes on your deployed site.

Want this checked on your site automatically?

AccessProof scans your site against WCAG 2.2 every day, scores it, and tells you exactly what to fix. Free plan available.