Site Header with Skip Links
Create an accessible site header with skip links for keyboard users. Ensure navigation landmarks are properly labeled and organized.
The Bad (Inaccessible)
<div class="header">
<div class="logo" onclick="location.href='/'">Brand</div>
<div class="nav">
<a href="/">Home</a>
<a href="/about">About</a>
</div>
</div>
Accessibility-Ready Code
<!-- Gold Standard: Semantic header with landmarks -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<header class="site-header">
<div class="header-container">
<!-- Logo with proper link -->
<a href="/" class="logo" aria-label="Company Home">
<img src="/logo.svg" alt="" width="150" height="50">
<span class="sr-only">Company</span>
</a>
<!-- Primary navigation -->
<nav id="navigation" aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About Us</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<!-- Secondary actions -->
<div class="header-actions">
<a href="/search" aria-label="Search">
<svg aria-hidden="true" width="20" height="20">π</svg>
</a>
<a href="/cart" aria-label="View cart (3 items)">
<svg aria-hidden="true" width="20" height="20">π</svg>
<span class="cart-count">3</span>
</a>
</div>
</div>
</header>
<!-- Main content -->
<main id="main-content">
<h1>Welcome</h1>
</main>
<style>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px 16px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
</style>
// Gold Standard: Semantic header with landmarks
a.skip-link(href="#main-content") Skip to main content
header.site-header
.header-container
// Logo with proper link
a.logo(href="/" aria-label="Company Home")
img(src="/logo.svg" alt="" width="150" height="50")
span.sr-only Company
// Primary navigation
nav#navigation(aria-label="Main navigation")
ul
li
a(href="/") Home
li
a(href="/about") About Us
li
a(href="/products") Products
li
a(href="/services") Services
li
a(href="/contact") Contact
// Secondary actions
.header-actions
a(href="/search" aria-label="Search")
svg(aria-hidden="true" width="20" height="20") π
a(href="/cart" aria-label="View cart (3 items)")
svg(aria-hidden="true" width="20" height="20") π
span.cart-count 3
// Main content
main#main-content
h1 Welcome
<>
<a href="#main-content" className="skip-link">
Skip to main content
</a>
<header className="site-header">
<div className="header-container">
<a href="/" className="logo" aria-label="Company Home">
<img src="/logo.svg" alt="" width="150" height="50" />
<span className="sr-only">Company</span>
</a>
<nav id="navigation" aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About Us</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<div className="header-actions">
<a href="/search" aria-label="Search">
<svg aria-hidden="true" width="20" height="20">π</svg>
</a>
<a href="/cart" aria-label="View cart (3 items)">
<svg aria-hidden="true" width="20" height="20">π</svg>
<span className="cart-count">3</span>
</a>
</div>
</div>
</header>
<main id="main-content">
<h1>Welcome</h1>
</main>
</>
<template>
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<header class="site-header">
<div class="header-container">
<a href="/" class="logo" aria-label="Company Home">
<img src="/logo.svg" alt="" width="150" height="50" />
<span class="sr-only">Company</span>
</a>
<nav id="navigation" aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About Us</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<div class="header-actions">
<a href="/search" aria-label="Search">
<svg aria-hidden="true" width="20" height="20">π</svg>
</a>
<a href="/cart" aria-label="View cart (3 items)">
<svg aria-hidden="true" width="20" height="20">π</svg>
<span class="cart-count">3</span>
</a>
</div>
</div>
</header>
<main id="main-content">
<h1>Welcome</h1>
</main>
</template>
<>
<a href="#main-content" class="absolute -top-10 left-0 bg-black text-white px-4 py-2 focus:top-0 z-[100]">
Skip to main content
</a>
<header class="bg-white border-b">
<div class="max-w-7xl mx-auto px-8 py-4 flex items-center justify-between">
<a href="/" class="logo" aria-label="Company Home">
<img src="/logo.svg" alt="" width="150" height="50" />
<span class="sr-only">Company</span>
</a>
<nav id="navigation" aria-label="Main navigation">
<ul class="flex space-x-8">
<li><a href="/" className="hover:text-blue-600">Home</a></li>
<li><a href="/about" className="hover:text-blue-600">About Us</a></li>
<li><a href="/products" className="hover:text-blue-600">Products</a></li>
<li><a href="/services" className="hover:text-blue-600">Services</a></li>
<li><a href="/contact" className="hover:text-blue-600">Contact</a></li>
</ul>
</nav>
<div class="flex space-x-4">
<a href="/search" aria-label="Search">
<span aria-hidden="true">π</span>
</a>
<a href="/cart" aria-label="View cart (3 items)">
<span aria-hidden="true">π</span>
<span class="cart-count">3</span>
</a>
</div>
</div>
</header>
<main id="main-content">
<h1>Welcome</h1>
</main>
</>
The Standard
Site headers provide navigation and branding. They must include skip links for keyboard users and proper landmark roles for screen readers.
WCAG Criteria
- 2.4.1 Bypass Blocks: Skip links to main content.
- 1.3.1 Info and Relationships: Semantic HTML structure.
- 4.1.2 Name, Role, Value: Proper ARIA roles.
β The Bad (Inaccessible)
Whatβs Wrong?
- No skip links: Keyboard users must tab through nav every page.
- Using
divfor header: No landmark for screen readers. - Missing nav labels: Screen readers canβt identify purpose.
onclickon logo: Not keyboard accessible.
β The Good (Accessibility-Ready Code)
Why This Works
- Skip Link: Lets keyboard users bypass repeated navigation.
- Semantic
<header>: Creates a banner landmark. - Labeled Navigation:
aria-labelidentifies the navβs purpose. - Proper Logo Link: Uses
<a>instead ofonclick.
Accessibility Checklist
- Add skip link as first focusable element in page.
- Use
<header role="banner">for site header. - Use
<nav aria-label="Main navigation">for primary nav. - Make logo an
<a>link, notonclick. - Add
aria-labelto icon-only links (search, cart). - Include item count in aria-label when relevant.
<a href="#main" class="skip-link">Skip to content</a>
<header role="banner">
<a href="/" aria-label="Company Home">
<img src="/logo.svg" alt="">
<span class="sr-only">Company</span>
</a>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<div class="header-actions">
<a href="/search" aria-label="Search">
<svg aria-hidden="true">...</svg>
</a>
<a href="/cart" aria-label="View cart (3 items)">
<svg aria-hidden="true">...</svg>
<span>3</span>
</a>
</div>
</header>
<main id="main">
<h1>Welcome</h1>
</main>
<style>
.skip-link {
position: absolute;
top: -40px;
}
.skip-link:focus {
top: 0;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
</style>
Technical Deep Dive
Screen Reader Announcements
- NVDA: βSkip to main content link, banner landmark, Main navigation navigationβ
- VoiceOver: βSkip to main content, link, navigation, Main navigationβ
- JAWS: βSkip to main content, link, banner region, Main navigationβ
Best Practice: Skip Link Visibility
Skip links should be visually hidden until they receive focus, then become visible. This is achieved using position: absolute; top: -40px to move the link off-screen, and top: 0 on :focus to bring it into view. Ensure skip links have a high z-index so they appear above all other content when focused.
Interactive Behavioral Lab
Interactive Sandbox
π¬ Technical Internals
Understand how this component is processed by the browser and Assistive Technology (AT). This section bridges the gap between visual code and the hidden logic that powers accessibility.
π² Accessibility Tree
The data structure used by screen readers to "see" your page. It translates HTML roles and attributes into standardized objects.
βοΈ Event Logic
Expected behavioral standards for keyboard navigation and state transitions. Crucial for users who don't use a mouse.
- Focus: Highlights via
:focus-visible - Activation: Responds to
EnterandSpace - Role: Identified as
Landmark