Skip to main content
Accessibility First: SkipLinks, ARIA Landmarks & Semantic HTML

Accessibility First: SkipLinks, ARIA Landmarks & Semantic HTML

Andrius LukminasAndrius LukminasFebruary 5, 20266 min read25 views

Accessibility isn't a feature you add later — it's a quality you build in from the start. When we audited Boottify's control center, we found that keyboard-only users couldn't efficiently navigate the admin panel. Tab focus would cycle through 40+ sidebar links before reaching the main content. That's not usable.

Here's how we fixed it across all three layout files in a single sprint.

THE AUDIT FINDINGS

We tested Boottify with a screen reader (NVDA) and keyboard-only navigation. The results:

  • No skip navigation — Keyboard users had to tab through the entire sidebar on every page
  • Missing ARIA landmarks — Screen readers couldn't identify page regions (nav, main, aside)
  • Non-semantic markup — Many <div> elements where <nav>, <main>, or <aside> should be
  • Focus indicators invisible — Custom styles had removed the default focus outlines

SKIPLINK COMPONENT

The SkipLink appears as the first focusable element on the page. It's visually hidden until it receives keyboard focus, then it slides into view at the top of the screen:

export function SkipLink() {
  return (
    <a
      href="#main-content"
      className="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2
                 focus:z-[9999] focus:px-4 focus:py-2 focus:bg-primary
                 focus:text-black focus:font-bold focus:outline-none"
    >
      Skip to main content
    </a>
  );
}

This single component saves keyboard users from tabbing through 40+ navigation items. One keypress takes them straight to the content.

ARIA LANDMARKS ACROSS 3 LAYOUTS

Boottify has three layout files that wrap all pages:

  • Auth layout (src/app/(auth)/layout.tsx) — Sign-in, sign-up, 2FA pages
  • Control center layout (src/app/(control-center)/layout.tsx) — Admin/client dashboard
  • Root layout (src/app/layout.tsx) — Landing pages, blog, public routes

Each layout now includes proper ARIA landmarks:

// Control center layout
<div className="flex min-h-screen">
  <SkipLink />
  <nav aria-label="Main navigation" role="navigation">
    <Sidebar />
  </nav>
  <main id="main-content" role="main" aria-label="Page content">
    {children}
  </main>
</div>

SEMANTIC HTML UPGRADES

We replaced non-semantic elements throughout the codebase:

BeforeAfterWhy
<div class="sidebar"><nav aria-label="Main navigation">Identifies as navigation landmark
<div class="content"><main id="main-content">SkipLink target + main landmark
<div class="footer"><footer role="contentinfo">Footer landmark for screen readers
<div class="header"><header role="banner">Banner landmark for site header

KEYBOARD FOCUS INDICATORS

Tailwind's focus:outline-none is widely used to remove "ugly" focus rings. The problem: it makes the interface unusable for keyboard users. We added a global focus style that's both accessible and on-brand:

/* globals.css */
*:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

The :focus-visible selector only shows the outline for keyboard navigation, not mouse clicks — the best of both worlds.

THE RESULT

After these changes, Boottify passes the following WCAG 2.1 AA criteria:

  • 2.4.1 Bypass Blocks — SkipLink provides mechanism to bypass navigation
  • 1.3.1 Info and Relationships — Semantic HTML conveys page structure
  • 2.4.7 Focus Visible — All interactive elements have visible focus indicators
  • 4.1.2 Name, Role, Value — ARIA attributes provide programmatic names

Accessibility improvements benefit everyone — not just users with disabilities. Keyboard shortcuts, screen reader support, and semantic structure also improve SEO, testing (Playwright can query by role), and code maintainability.

Related Articles

Comments

0/5000 characters

Comments from guests require moderation.