Missing Skip Links
What This Means
Skip links (also called skip navigation links) are hidden links that allow keyboard and screen reader users to bypass repetitive navigation and jump directly to main content. Without skip links, users must tab through dozens of navigation items on every page to reach the content they want.
Impact on Your Business
Legal Compliance:
- Skip links are recommended by WCAG 2.1 Level A (Success Criterion 2.4.1 Bypass Blocks)
- Required for Section 508 compliance
- Common accessibility audit finding
- Demonstrates commitment to inclusive design
User Experience:
- Keyboard users must tab through entire navigation on every page without skip links
- Screen reader users hear the same navigation menu repeatedly
- Skip links can reduce navigation time from 30+ tab presses to 1
- Improves experience for power users who prefer keyboard navigation
Efficiency Benefits:
- Users reach content faster
- Reduces frustration and abandonment
- Improves task completion rates
- Shows professionalism and attention to detail
SEO & Technical Benefits:
- Demonstrates semantic HTML structure
- Signals good information architecture
- Improves perceived performance for keyboard users
- Enhances overall site usability
How to Diagnose
Method 1: Keyboard Testing (Recommended)
- Navigate to your website
- Press Tab key once (before clicking anywhere)
- What to look for:
- Skip link should appear as the first focusable element
- Typically says "Skip to main content" or "Skip to content"
- Should be visibly highlighted when focused
- Should disappear when focus moves away
Missing skip link indicators:
- First tab focuses on logo or first navigation link
- No visible "skip" option appears
- Must tab through 10+ items to reach content
Method 2: Visual Inspection
- View page source or use DevTools Inspector
- Look at the beginning of
<body>tag - Search for skip link patterns:
<!-- Good examples -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<a href="#content" class="skip-to-content">Skip to content</a>
<a href="#main">Skip navigation</a>
<!-- Missing - no skip link present -->
<body>
<header>
<nav>...</nav>
</header>
What to look for:
- Link should be one of the first elements in
<body> - Should link to an ID (href="#main-content")
- Target ID should exist on the page
- May have CSS class like "skip-link" or "sr-only"
Method 3: WAVE Browser Extension
- Install WAVE Extension
- Navigate to your webpage
- Click the WAVE icon
- Look in the Features section for:
- Skip link feature icon (green, looks like a forward arrow)
- If present: skip link exists but verify it works
- If missing: no skip link detected
What to look for:
- Presence or absence of skip link feature
- Whether skip link target exists
- Whether skip link is keyboard accessible
Method 4: axe DevTools
- Install axe DevTools Extension
- Open Chrome DevTools (F12)
- Navigate to "axe DevTools" tab
- Click "Scan ALL of my page"
- Check Best Practices section for:
- "Page should contain a heading, skip link, or landmark region"
- "Bypass Blocks" warnings
What to look for:
- Best practices violations
- Warnings about missing bypass mechanisms
- Recommendations to add skip links
Method 5: Screen Reader Testing
Start screen reader:
- Windows: NVDA (free)
- Mac: VoiceOver (Cmd+F5)
- Chrome: ChromeVox extension
Navigate to page and press Tab
Listen for first announcement
What to look for:
- First tab should announce "Skip to main content, link" or similar
- If first announcement is "Home, link" or navigation item, skip link is missing
- Skip link should be easily accessible without extensive navigation
Method 6: Lighthouse Accessibility Audit
- Open Chrome DevTools (F12)
- Navigate to "Lighthouse" tab
- Select "Accessibility" category
- Click "Generate report"
- Look for:
- "Bypass Blocks" in manual checks
- Recommendations about skip links
- Overall navigation accessibility score
What to look for:
- Manual check reminders about bypass blocks
- Whether page has mechanisms to skip navigation
- Recommendations in accessibility report
General Fixes
Fix 1: Add Basic Skip to Main Content Link
Simplest implementation:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Title</title>
<style>
/* Skip link styles */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
text-decoration: none;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
</style>
</head>
<body>
<!-- Skip link should be first focusable element -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>
<nav>
<!-- Navigation items -->
</nav>
</header>
<main id="main-content" tabindex="-1">
<!-- Main content here -->
<h1>Page Heading</h1>
<p>Content...</p>
</main>
</body>
</html>
Key requirements:
- Link must be first focusable element in
<body> - Must link to valid ID that exists on page
- Target element should have
tabindex="-1"to receive focus - Must be visually hidden but appear on focus
Fix 2: Enhanced Skip Link with Multiple Targets
For complex layouts with multiple skip options:
<body>
<div class="skip-links">
<a href="#main-content" class="skip-link">Skip to main content</a>
<a href="#navigation" class="skip-link">Skip to navigation</a>
<a href="#footer" class="skip-link">Skip to footer</a>
</div>
<header>
<nav id="navigation">
<!-- Navigation -->
</nav>
</header>
<main id="main-content" tabindex="-1">
<!-- Main content -->
</main>
<footer id="footer" tabindex="-1">
<!-- Footer content -->
</footer>
</body>
Enhanced CSS for multiple skip links:
.skip-links {
position: relative;
}
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px 12px;
text-decoration: none;
border-radius: 0 0 4px 0;
z-index: 100;
transition: top 0.2s;
}
.skip-link:focus {
top: 0;
outline: 3px solid #4a90e2;
outline-offset: 2px;
}
.skip-link:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
When to use multiple skip links:
- Pages with extensive navigation
- Sites with sidebars or multiple content areas
- Long pages with multiple sections
- Complex application interfaces
Fix 3: Accessible Skip Link Implementation
Production-ready implementation:
<head>
<style>
/* Visually hidden but screen-reader accessible */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* Skip link visible on focus */
.skip-link {
position: fixed;
top: 0;
left: 0;
background: #000;
color: #fff;
padding: 10px 15px;
text-decoration: none;
font-weight: bold;
z-index: 9999;
transform: translateY(-100%);
transition: transform 0.3s;
}
.skip-link:focus {
transform: translateY(0);
}
</style>
</head>
<body>
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<header>
<nav aria-label="Main navigation">
<!-- Navigation -->
</nav>
</header>
<main id="main-content" tabindex="-1">
<h1>Page Title</h1>
<!-- Main content -->
</main>
</body>
JavaScript to ensure focus moves to target:
// Enhance skip link to ensure focus moves properly
document.addEventListener('DOMContentLoaded', function() {
const skipLinks = document.querySelectorAll('.skip-link');
skipLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href').substring(1);
const target = document.getElementById(targetId);
if (target) {
target.setAttribute('tabindex', '-1');
target.focus();
// Scroll to target
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
});
Why this approach works:
- Fixed positioning keeps link in same place
- Transform animation provides smooth appearance
- High z-index ensures visibility over other content
- JavaScript ensures consistent focus behavior across browsers
Fix 4: Skip Links with ARIA Landmarks
Combining skip links with ARIA landmarks:
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header role="banner">
<nav role="navigation" aria-label="Main">
<!-- Primary navigation -->
</nav>
</header>
<aside role="complementary" aria-label="Sidebar">
<!-- Sidebar content -->
</aside>
<main id="main-content" role="main" tabindex="-1">
<h1>Page Heading</h1>
<!-- Main content -->
</main>
<footer role="contentinfo">
<!-- Footer content -->
</footer>
</body>
Benefits of combining approaches:
- Skip links provide keyboard shortcut to content
- ARIA landmarks provide screen reader navigation
- HTML5 semantic elements (
<main>,<nav>,<aside>) automatically create landmarks - Multiple navigation methods improve overall accessibility
Screen reader landmark navigation:
- NVDA: D key (landmarks), M key (main landmark)
- VoiceOver: VO+U, then left/right arrows to Landmarks
- JAWS: ; key (next landmark), Shift+; (previous landmark)
Fix 5: Platform-Specific Implementations
WordPress (in theme files):
<!-- header.php -->
<body <?php body_class(); ?>>
<a class="skip-link screen-reader-text" href="#content">
<?php esc_html_e( 'Skip to content', 'textdomain' ); ?>
</a>
<!-- Navigation -->
<main id="content" class="site-content" tabindex="-1">
<?php
// Content
?>
</main>
// components/SkipLink.jsx
export default function SkipLink() {
return (
<a
href="#main-content"
className="skip-link"
onClick={(e) => {
e.preventDefault();
const main = document.getElementById('main-content');
if (main) {
main.focus();
main.scrollIntoView({ behavior: 'smooth' });
}
}}
>
Skip to main content
</a>
);
}
// app/layout.jsx or pages/_app.jsx
export default function Layout({ children }) {
return (
<>
<SkipLink />
<Header />
<main id="main-content" tabIndex={-1}>
{children}
</main>
<Footer />
</>
);
}
Shopify (theme.liquid):
<body class="template-{{ template.name }}">
<a class="skip-link" href="#MainContent">
{{ 'accessibility.skip_to_text' | t }}
</a>
{% section 'header' %}
<main id="MainContent" class="content-for-layout" role="main" tabindex="-1">
{{ content_for_layout }}
</main>
{% section 'footer' %}
</body>
Common Mistakes
- Skip link not first focusable element - Must be first tab stop
- Target ID doesn't exist - Link goes nowhere
- Target not focusable - Missing
tabindex="-1"on target - Skip link always visible - Should be hidden until focused
- Skip link not visible when focused - Defeats the purpose
- Multiple skip links to same target - Redundant and confusing
- Skip link inside navigation - Defeats bypass purpose
- Using display:none - Makes link unfocusable
- Generic text - "Skip link" instead of "Skip to main content"
- Missing z-index - Link hidden behind other elements
Verification
After implementing skip links:
Keyboard test:
- Refresh page
- Press Tab once
- Verify skip link appears and is highlighted
- Press Enter
- Verify focus moves to main content
- Verify page scrolls if needed
Screen reader test:
- Navigate to page with screen reader
- Press Tab
- Verify "Skip to main content, link" is announced
- Activate link
- Verify focus moves to content area
- Verify new location is announced
WAVE validation:
- Run WAVE extension
- Verify skip link feature appears (green icon)
- Verify no errors related to skip link
- Check that target ID exists
Visual inspection:
- View page source
- Verify skip link is first in
<body> - Verify target ID matches href
- Verify target element has tabindex="-1"
Browser compatibility:
- Test in Chrome, Firefox, Safari, Edge
- Verify consistent behavior
- Check mobile keyboard navigation
- Test with different screen reader + browser combinations
Platform-Specific Guides
Detailed implementation instructions for your specific platform:
| Platform | Troubleshooting Guide |
|---|---|
| Shopify | Shopify Skip Links Guide |
| WordPress | WordPress Skip Links Guide |
| Wix | Wix Skip Links Guide |
| Squarespace | Squarespace Skip Links Guide |
| Webflow | Webflow Skip Links Guide |