Missing Skip Links | Blue Frog Docs

Missing Skip Links

Diagnose and implement skip navigation links to improve keyboard accessibility and screen reader experience

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

  1. Navigate to your website
  2. Press Tab key once (before clicking anywhere)
  3. 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

  1. View page source or use DevTools Inspector
  2. Look at the beginning of <body> tag
  3. 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

  1. Install WAVE Extension
  2. Navigate to your webpage
  3. Click the WAVE icon
  4. 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

  1. Install axe DevTools Extension
  2. Open Chrome DevTools (F12)
  3. Navigate to "axe DevTools" tab
  4. Click "Scan ALL of my page"
  5. 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

  1. Start screen reader:

    • Windows: NVDA (free)
    • Mac: VoiceOver (Cmd+F5)
    • Chrome: ChromeVox extension
  2. Navigate to page and press Tab

  3. 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

  1. Open Chrome DevTools (F12)
  2. Navigate to "Lighthouse" tab
  3. Select "Accessibility" category
  4. Click "Generate report"
  5. 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

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

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

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>

React/Next.js:

// 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

  1. Skip link not first focusable element - Must be first tab stop
  2. Target ID doesn't exist - Link goes nowhere
  3. Target not focusable - Missing tabindex="-1" on target
  4. Skip link always visible - Should be hidden until focused
  5. Skip link not visible when focused - Defeats the purpose
  6. Multiple skip links to same target - Redundant and confusing
  7. Skip link inside navigation - Defeats bypass purpose
  8. Using display:none - Makes link unfocusable
  9. Generic text - "Skip link" instead of "Skip to main content"
  10. Missing z-index - Link hidden behind other elements

Verification

After implementing skip links:

  1. 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
  2. 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
  3. WAVE validation:

    • Run WAVE extension
    • Verify skip link feature appears (green icon)
    • Verify no errors related to skip link
    • Check that target ID exists
  4. Visual inspection:

    • View page source
    • Verify skip link is first in <body>
    • Verify target ID matches href
    • Verify target element has tabindex="-1"
  5. 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

Additional Resources

// SYS.FOOTER