Skip to content

[A11Y] [Medium] Missing skip navigation link #4

@continue

Description

@continue

Accessibility Issue: Missing Skip Navigation Link

WCAG Level: A
Severity: Medium
Category: Skip Links & Navigation (WCAG 2.4.1)

Issue Description

The application lacks a "Skip to main content" link, forcing keyboard and screen reader users to tab through the entire navigation menu on every page load.

User Impact

  • Affected Users: Keyboard-only users, screen reader users, motor disability users
  • Severity: Medium - repetitive navigation significantly impacts usability

Violations Found

File: src/App.tsx

Lines: 26-56

<!-- Current Code -->
function AppShell() {
  return (
    <div className="app">
      <nav className="nav">
        <NavLink to="/" className="nav-brand" end>
          <img src={logoUrl} alt="Apollo" className="nav-brand-logo" />
          <span className="nav-brand-text">Apollo</span>
        </NavLink>
        <div className="nav-links">
          {/* 6 navigation links that users must tab through */}
        </div>
      </nav>
      <main className="main">
        {/* Main content */}
      </main>
    </div>
  );
}

Issue: No mechanism to bypass repeated navigation blocks.


Recommended Fix

<!-- Fixed Code - App.tsx -->
function AppShell() {
  return (
    <div className="app">
      {/* Skip link - first focusable element */}
      <a 
        href="#main-content" 
        className="skip-link"
      >
        Skip to main content
      </a>
      
      <nav className="nav" aria-label="Main navigation">
        <NavLink to="/" className="nav-brand" end>
          <img src={logoUrl} alt="Apollo" className="nav-brand-logo" />
          <span className="nav-brand-text">Apollo</span>
        </NavLink>
        <div className="nav-links">
          {/* Navigation links */}
        </div>
      </nav>
      
      <main id="main-content" className="main" tabIndex={-1}>
        <PageWrapper>
          <Routes>
            {/* Routes */}
          </Routes>
        </PageWrapper>
      </main>
    </div>
  );
}
/* Add to index.css or App.css */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: var(--apollo-gold);
  color: var(--apollo-navy);
  padding: 8px 16px;
  z-index: 100;
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 var(--radius-md) 0;
  transition: top 0.2s ease;
}

.skip-link:focus {
  top: 0;
}

Changes Made:

  1. Add skip link as first focusable element in the app
  2. Link targets #main-content id on main element
  3. Add tabIndex={-1} to main for programmatic focus management
  4. Add aria-label to nav element
  5. Style skip link to be visually hidden until focused

Additional Improvements

  • Consider adding skip links for other repeated content sections
  • Add aria-current="page" to active navigation link (NavLink may handle this)
  • Manage focus on route changes

Testing Instructions

  1. Load any page in the application
  2. Press Tab as first action - skip link should appear
  3. Press Enter on skip link
  4. Verify focus moves to main content area
  5. Subsequent Tab should focus first interactive element in main content

Resources

Acceptance Criteria

  • Skip link is first focusable element on page
  • Skip link is visually hidden until focused
  • Skip link has clear, descriptive text
  • Activating skip link moves focus to main content
  • Works correctly on all pages
  • Tested with keyboard navigation

Metadata

Metadata

Assignees

No one assigned

    Labels

    accessibilityAccessibility improvementsseverity-mediumMedium severity - notable impactwcag-aWCAG Level A compliance

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions