You Might Also Like
Accessible Skip to Content Link — Free HTML CSS JS Snippet
Accessible Skip to Content Link · Navigation · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Accessible Skip to Content Link — WCAG Skip-Navigation Pattern with Focus-Triggered Visibility

A skip-to-content link is one of the oldest and most consequential patterns in web accessibility, and it is also one of the most commonly implemented incorrectly. Its job is simple: let a keyboard user or screen-reader user bypass a page's repeated navigation, header, and search widgets and jump straight to the unique content of the page, without having to tab through every menu item first. WCAG 2.2 Success Criterion 2.4.1 (Bypass Blocks) requires exactly this mechanism, and it is one of the first things an accessibility audit checks. This snippet implements the pattern correctly: a link that is invisible until it receives keyboard focus, then appears clearly at the top of the viewport with a high-contrast, unmistakable focus style.
The bug class this snippet avoids
The single most common mistake in skip-link implementations is hiding the link with display: none or visibility: hidden. Both properties remove an element from the accessibility tree entirely — a screen reader will never announce it, and more critically, a hidden element with display: none cannot receive focus at all, so a sighted keyboard user pressing Tab will simply skip over it as if it does not exist. The link becomes permanently unreachable rather than temporarily hidden, which defeats its entire purpose while still satisfying a naive "is there a skip link in the HTML" checklist item. This is exactly the kind of accessibility bug that passes a cursory code review and fails every real assistive-technology test.
The correct technique: absolute positioning off-screen
This snippet instead uses position: absolute with top: -48px to push the link above the visible viewport while keeping it fully present in the layout and, crucially, in the tab order and accessibility tree. Because the element is still rendered (just positioned outside the visible area), a screen reader announces it in document order exactly like any other link, and pressing Tab from the top of the page moves focus to it normally. The reveal happens entirely through the :focus pseudo-class: .skip-link:focus { top: 12px; } animates the link back into the viewport with a transition: top 0.2s ease, paired with a strong outline: 3px solid #6366f1 so sighted keyboard users get an unmistakable visual cue that focus has landed somewhere new. The moment focus moves away — either by tabbing onward or activating the link — it slides back off-screen.
Why the destination needs `tabindex="-1"`
Activating the skip link needs to do more than change the URL hash; it needs to move actual keyboard focus to the main content landmark so the very next Tab press continues from there, not from the top of the page again. The <main id="main-content" tabindex="-1"> element is not naturally focusable — only interactive elements like links, buttons, and form fields are — so tabindex="-1" is added specifically to make it a valid, though not tab-reachable, focus target. The JavaScript calls mainContent.focus() on click, which combined with the browser's native hash-jump from href="#main-content" produces the complete bypass behaviour: the viewport scrolls to the content and keyboard focus lands there simultaneously.
Why this matters for 2026 accessibility-first design
Accessibility-first design is no longer a compliance checkbox tacked on before launch — regulatory pressure (the European Accessibility Act, ADA Title II digital rules, WCAG 2.2 as the emerging baseline) and genuine product quality expectations have made keyboard and screen-reader usability a first-class design requirement from day one. A skip link is one of the highest-leverage accessibility investments a page can make: it costs almost nothing to build correctly, and it directly determines whether keyboard and assistive-technology users can efficiently use a site with a large navigation, or whether every single page load costs them dozens of extra keystrokes. Getting the off-screen mechanic right, rather than reaching for display: none, is the difference between a pattern that looks done and one that actually works.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to trace exactly why position: absolute with a negative top offset keeps the link keyboard-reachable while display: none would not — it's a great way to actually internalize the accessibility-tree distinction rather than memorizing a rule. You can also ask it to extend the pattern to a second "Skip to footer" link stacked below the first, or to adapt the reveal animation to a slide-from-left instead of slide-from-top while preserving the same off-screen/focus mechanics. Another good ask: have it audit a real page of yours for elements hidden with display: none or visibility: hidden that should instead be visually-hidden-but-focusable, since that exact mistake is the most common cause of broken skip links and broken accessibility labels in production codebases. Treat this less as a copy-paste widget and more as the reference case for a pattern that recurs throughout accessible UI work.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a WCAG-compliant "skip to main content" link in plain HTML, CSS, and JavaScript.
Requirements:
- The link must be the first focusable element in the document, placed before any header or navigation markup.
- It must remain fully present in the DOM and in the natural tab order at all times — do not use display: none or visibility: hidden at any point, since both remove an element from the accessibility tree and make it unfocusable.
- Instead, hide it visually by positioning it off-screen (for example position: absolute with a negative top or left offset) while it is unfocused, and reveal it with a smooth CSS transition when it receives keyboard focus via the :focus pseudo-class.
- The revealed state must have a clearly visible, high-contrast focus indicator (background, text color, and outline) that meets accessible contrast ratios against the page background.
- Clicking or activating the link (Enter key while focused) must move actual keyboard focus to the main content landmark, not just scroll to it — give the landmark id="main-content" and tabindex="-1" so it becomes a valid programmatic focus target, and call element.focus() on it in JavaScript.
- Build a small demo page around it with a realistic multi-item navigation bar before the main content, so the practical benefit of skipping it is obvious.
- Add a visible status indicator in the demo that confirms when the skip link has actually been activated versus merely focused, for clarity during manual testing.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Click into the preview, then press TabClick anywhere on the light grey preview background first so the demo iframe has focus, then press Tab once. The "Skip to main content" link slides down from off-screen into view at the top-left with a high-contrast dark background and a visible indigo focus outline.
- 2Activate the link to jump past the navPress Enter (or click the visible link) while it is focused. Focus moves directly to the #main-content landmark — notice the status line updates and the page does not require tabbing through the nine nav links above it to get there.
- 3Understand the CSS mechanicInspect .skip-link in the CSS panel: it uses position: absolute; top: -48px to sit outside the viewport while remaining in the DOM and tab order. The .skip-link:focus rule sets top: 12px, animated by transition: top 0.2s ease, to bring it into view only when it actually has focus.
- 4Place it as the very first focusable elementA skip link only works if it is the first tabbable element on the page — before the logo, before the nav, before any cookie banner. In the HTML panel it sits immediately as the first child, before .demo-header, which is exactly where it must go in your real layout.
- 5Add tabindex="-1" to your real main landmarkIn your own app, add id="main-content" tabindex="-1" to the <main> element (or the first heading inside it). Without tabindex="-1", calling mainContent.focus() in JS silently does nothing in most browsers because non-interactive elements are not programmatically focusable by default.
- 6Export and adapt for multi-region pagesClick HTML or JSX to export. For pages with multiple landmarks (nav, main, footer), consider adding a second skip link ("Skip to footer") using the same off-screen/focus pattern, stacked with a slightly larger top offset so both remain reachable and visually distinct when tabbed to in sequence.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
display: none removes an element from the accessibility tree and, critically, makes it impossible to focus in the first place — a keyboard user tabbing through the page would skip right over it because there is nothing there to receive focus. You cannot use JavaScript to detect a focus event that can never fire. Off-screen positioning with position: absolute keeps the link fully present and focusable at all times; only its visual location changes on :focus.
Only naturally interactive elements (links, buttons, inputs, elements with a native tabindex) can receive keyboard focus by default. A <main> or <div> landmark is not interactive, so calling element.focus() on it does nothing in most browsers unless it has tabindex="-1", which makes it programmatically focusable without adding it to the natural Tab order. This lets the skip link move real focus there, so the next Tab press continues from inside the content rather than jumping back to the top of the page.
Yes — its entire value depends on being the first (or one of the first) tabbable elements a keyboard user encounters. If it appears after the logo, search box, or any other focusable element, users still have to tab past those first, which defeats the purpose. Place it immediately inside the opening body tag, before any header, nav, or cookie-consent banner markup.
Landmark regions help screen-reader users navigate by region using rotor or landmark-jump commands, but they do nothing for sighted keyboard-only users who rely purely on the Tab key, and not every screen reader user relies on landmark navigation exclusively. A visible, focusable skip link is still required by WCAG 2.4.1 and remains the most universally supported bypass mechanism across assistive technologies and keyboard-only use.
Yes — any colours work as long as the focused state maintains strong contrast against the page background (WCAG requires at least 3:1 contrast for the focus indicator itself and 4.5:1 for the link text against its own background). Keep the position: absolute plus top offset plus :focus reveal structure intact; only the background, text colour, border-radius, and outline colour are safe to customise.