Keyboard users must tab through every navigation link on every page visit without a way to skip to main content.
Most websites have navigation menus with 10, 20, or more links. Keyboard users must press Tab for each link before reaching the main content. On a site with 30 nav links, that's 30 key presses per page. Bypass mechanisms—skip links, headings, and landmark regions—let users jump directly to what they need. WCAG requires at least one bypass method for pages with repeated blocks of content.
<h1>)<main>, <nav>, <header>, <footer>Use a screen reader's landmarks navigation (NVDA: D key, VoiceOver: rotor) to verify landmarks are recognized.
Place a skip link as the first focusable element on the page:
<body>
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<header>
<nav><!-- 20+ navigation links --></nav>
</header>
<main id="main-content">
<!-- Page content -->
</main>
</body>
Style the skip link to be visible only on focus:
.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;
}
Screen readers can navigate by landmarks directly:
<body>
<header role="banner">
<nav role="navigation" aria-label="Main">
<!-- Navigation links -->
</nav>
</header>
<main role="main">
<h1>Page Title</h1>
<!-- Main content -->
</main>
<aside role="complementary">
<!-- Sidebar content -->
</aside>
<footer role="contentinfo">
<!-- Footer content -->
</footer>
</body>
Note: Modern browsers don't require explicit roles on semantic elements, but they don't hurt.
Every page should have at least one heading:
<main id="main-content">
<h1>Welcome to Our Site</h1>
<section>
<h2>Featured Products</h2>
<!-- Content -->
</section>
<section>
<h2>Latest News</h2>
<!-- Content -->
</section>
</main>
Screen reader users can press H to jump between headings, providing another bypass method.
When you have multiple <nav> elements, label them:
<nav aria-label="Main navigation">
<!-- Primary nav links -->
</nav>
<nav aria-label="Breadcrumb">
<!-- Breadcrumb links -->
</nav>
<nav aria-label="Footer navigation">
<!-- Footer links -->
</nav>
<!-- layouts/default.vue -->
<template>
<div>
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<AppHeader />
<main id="main-content">
<slot />
</main>
<AppFooter />
</div>
</template>
<style>
.skip-link {
@apply absolute -top-10 left-0 bg-primary text-white px-4 py-2 z-50 focus:top-0 transition-[top];
}
</style>
href="#main-content" must match an element's id.<main id="main-content">.<div class="main"> isn't a landmark. Use <main> or add role="main".Lighthouse looks for at least one of:
<h1> through <h6>)<a> with an anchor reference early in the DOM)<main>, <nav>, <header>, <footer>, or elements with landmark roles)For the best user experience, implement all three: skip link, proper headings, and semantic landmarks.
Bypass issues often appear alongside:
Navigation structure and bypass blocks should be consistent across your site. Unlighthouse audits every page to ensure your skip links work everywhere, your heading structure is consistent, and all pages have proper landmark regions for screen reader navigation.