When to use
Always — on every page that has more than a handful of links between the top of the document and the main content. Sighted mouse users never see it. Keyboard users press Tab once and skip the lot.
The pattern
Tab into the demo above to reveal the skip link. Activate it and focus jumps here, past the nav.
The whole pattern is two HTML elements and a few lines of CSS:
<a href="#main" class="skip-link">Skip to main content</a>
<header>…site nav…</header>
<main id="main" tabindex="-1">
…
</main> The tabindex="-1" on <main> is what lets the link actually move focus there. Without it, modern browsers move visual scroll position to the target but leave keyboard focus where it was — so the next Tab keypress dumps the user back into the nav they tried to skip.
Visible on focus, not on hover
The skip link should be invisible until a keyboard user reaches it, then unmistakable:
.skip-link {
position: absolute;
inset-inline-start: 1rem;
inset-block-start: 1rem;
padding: 0.5rem 1rem;
background: var(--color-accent);
color: var(--color-accent-fg);
text-decoration: none;
border-radius: 0.5rem;
transform: translateY(-150%);
transition: transform 150ms;
z-index: 100;
}
.skip-link:focus {
transform: translateY(0);
} :focus (not :focus-visible) on purpose — we want the link to appear for any focus, including programmatic. The :focus-visible variant would still work for keyboard users, but :focus is more permissive and the link is harmless for mouse users to occasionally see.
Don’t display: none or visibility: hidden it — both remove the link from the focus order entirely.
Anti-pattern: hidden by display: none
The most common mistake. The link is in the markup but uses display: none “until needed”:
.skip-link {
display: none;
}
.skip-link:focus {
display: block;
} display: none removes the element from the accessibility tree, the focus order, and the rendering tree. The :focus rule never matches, because the link can’t be focused. Tab walks straight past it as if it weren’t there.
The same trap applies to visibility: hidden and hidden.
Common variations
- Multiple landmarks — for pages with substantial regions, ship multiple skip links: “Skip to main”, “Skip to search”, “Skip to footer”. They appear in sequence on Tab.
- Skip-to-search — common on documentation sites. Useful when the search input is well below the nav.
- In-page skip — within a long article, “Jump to comments” links from the top of the post.
- Single-page apps — when the route changes, focus may stay on the link the user clicked. Move focus to
<h1>(or the new<main>) so the skip-link logic still applies after navigation.
Checklist
- First focusable element on the page (top of the DOM)
- Visible whenever it has focus (not just hover)
- Target element has
idmatching the link’shref - Target element has
tabindex="-1"so focus actually moves there - Visible focus indicator on the link itself
- Hit area at least 44×44 CSS pixels for AAA
- Not hidden via
display: none/visibility: hidden/hidden