In-Page Anchor Links
Create accessible jump links within a page. Use ID attributes and semantic linking for keyboard and screen reader users.
The Bad (Inaccessible)
<a href="#section" class="smooth-scroll">Jump to Section</a>
<div id="section">Content</div>
Accessibility-Ready Code
<!-- Gold Standard: Skip link with proper focus management -->
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<!-- In-page navigation -->
<nav aria-label="Page contents">
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#pricing">Pricing</a></li>
</ul>
</nav>
<!-- Main content with id -->
<main id="main-content">
<section id="introduction">
<h2>Introduction</h2>
</section>
<section id="features">
<h2>Features</h2>
</section>
<section id="pricing">
<h2>Pricing</h2>
</section>
</main>
// Gold Standard: Skip link with proper focus management
a(href="#main-content" class="skip-link") Skip to main content
// In-page navigation
nav(aria-label="Page contents")
ul
li
a(href="#introduction") Introduction
li
a(href="#features") Features
li
a(href="#pricing") Pricing
// Main content with id
main#main-content
section#introduction
h2 Introduction
section#features
h2 Features
section#pricing
h2 Pricing
const InPageNav = () => (
<>
<a href="#main-content" className="skip-link">
Skip to main content
</a>
<nav aria-label="Page contents">
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#pricing">Pricing</a></li>
</ul>
</nav>
<main id="main-content">
<section id="introduction">
<h2>Introduction</h2>
</section>
<section id="features">
<h2>Features</h2>
</section>
<section id="pricing">
<h2>Pricing</h2>
</section>
</main>
</>
);
<template>
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<nav aria-label="Page contents">
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#pricing">Pricing</a></li>
</ul>
</nav>
<main id="main-content">
<section id="introduction">
<h2>Introduction</h2>
</section>
<section id="features">
<h2>Features</h2>
</section>
<section id="pricing">
<h2>Pricing</h2>
</section>
</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>
<nav aria-label="Page contents">
<ul class="flex space-x-6">
<li><a href="#introduction" class="text-blue-600 hover:underline">Introduction</a></li>
<li><a href="#features" class="text-blue-600 hover:underline">Features</a></li>
<li><a href="#pricing" class="text-blue-600 hover:underline">Pricing</a></li>
</ul>
</nav>
<main id="main-content">
<section id="introduction">
<h2>Introduction</h2>
</section>
<section id="features">
<h2>Features</h2>
</section>
<section id="pricing">
<h2>Pricing</h2>
</section>
</main>
The Standard
In-page anchor links help users navigate within a long page. Skip links are essential for keyboard users to bypass repeated navigation and jump directly to main content.
WCAG Criteria
- 2.4.1 Bypass Blocks: Provide a way to bypass repeated content.
- 2.4.7 Focus Visible: Make the focused element visible.
❌ The Bad (Inaccessible)
What’s Wrong?
- No Focus Management: The anchor jumps but doesn’t move focus, so keyboard users can’t continue from that point.
- Missing Skip Link: Keyboard users must tab through entire navigation on every page.
- Poor Visual Indicator: The skip link is hidden until focused, but may not have visible focus styles.
✅ The Good (Accessibility-Ready Code)
Why This Works
- Skip Link: Allows keyboard users to bypass navigation with a single click.
- Focus Management: JavaScript ensures the target element receives focus when the link is clicked.
- Visible Focus Indicator: The skip link appears when focused, making it discoverable.
Accessibility Checklist
- Provide a “Skip to main content” link as the first focusable element.
- Make skip links visible on focus (
:focusCSS). - Position skip links off-screen (
position: absolute; top: -40px) until focused. - Ensure target elements have matching
idattributes. - Add
aria-labelto navigation for context. - Use semantic
<nav>for navigation sections.
<a href="#main" class="skip-link">Skip to content</a>
<style>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
}
.skip-link:focus {
top: 0;
}
</style>
<main id="main">
<h1>Welcome</h1>
</main>
Technical Deep Dive
Screen Reader Announcements
- NVDA: “Introduction, link”
- VoiceOver: “Introduction, link”
- JAWS: “Introduction, link”
Best Practice: Focus Management for In-Page Anchors
When users click an in-page anchor, the browser scrolls to the target but doesn’t move focus. For keyboard users, this means they must tab through all content between the anchor and the target. To fix this, add a small script that manages focus when anchors are clicked, ensuring keyboard and mouse users have the same experience.
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
Link