Every page on your site repeats the same header, navigation menu, and search box before the content that actually matters. For a keyboard-only or screen reader user, that means pressing Tab repeatedly, on every single page, just to reach the article they came for. Skip links and landmarks are the two mechanisms that fix this, and WCAG 2.4.1 Bypass Blocks (Level A) requires at least one of them.
This guide covers both the way a developer actually implements them: a working skip link that becomes visible on focus, the correct HTML5 and ARIA landmark structure for header, nav, main, and footer, and the focus-management detail that silently breaks most skip links in the wild. Get these right and you clear a Level A success criterion that EAA conformance under EN 301 549 depends on.
What WCAG 2.4.1 Bypass Blocks actually requires
Success Criterion 2.4.1 Bypass Blocks (Level A) says you must provide a mechanism to skip blocks of content that are repeated across pages. The header, primary navigation, and any cookie or promo bar that appears on every page all count as repeated blocks. The criterion is satisfied if either of two techniques is present and functional.
- A skip link as the first focusable element, jumping past the repeated block straight to the main content.
- Proper landmark structure (HTML5 sectioning elements or ARIA roles) that lets assistive technology jump between regions.
In a single-page app or a flat document with no headings or landmarks, neither is present and you fail at Level A. Because the European Accessibility Act (in force since 28 June 2025) sets WCAG 2.2 Level A and AA as the baseline through EN 301 549, this is not optional for in-scope products. See our overview of the European Accessibility Act for the legal framing.
Landmarks: header, nav, main, footer (and their ARIA roles)
HTML5 sectioning elements carry implicit ARIA roles, so in most cases you should reach for the native element rather than adding role attributes by hand. The mapping is direct:
- <header> at the top level maps to role="banner" (site header). Nested inside <article> or <main>, it is NOT a banner, just a header.
- <nav> maps to role="navigation". Use it for major navigation blocks, not for every list of links.
- <main> maps to role="main". There must be exactly one per page, and it must not be nested inside article, aside, header, footer, or nav.
- <footer> at the top level maps to role="contentinfo". Like header, it loses that role when nested inside article or main.
- <aside> maps to role="complementary", <form> with an accessible name maps to role="form", and <section> with a name maps to role="region".
A clean page skeleton therefore reads as: <header>…</header>, <nav aria-label="Primary">…</nav>, <main id="main-content" tabindex="-1">…</main>, <footer>…</footer>. That structure alone gives screen reader users a landmarks menu they can jump through, satisfying half of 2.4.1.
Naming duplicate landmarks
If you have two nav landmarks, say a primary menu and a footer menu, give each a distinct accessible name with aria-label (for example aria-label="Primary" and aria-label="Footer"). Unnamed duplicate landmarks of the same type are ambiguous in a screen reader's landmark list and are a recurring audit finding. The same rule applies to multiple region or complementary landmarks.
Building a skip link that works
Landmarks help assistive technology, but a sighted keyboard user, someone with a motor impairment using Tab, or a power user, gets no benefit from them. For that audience, the skip link is the mechanism. It must be the first focusable element in the DOM, before the logo and nav, so the very first Tab press lands on it.
The markup is a plain in-page anchor pointing at the main element's id:
- The link: <a class="skip-link" href="#main-content">Skip to main content</a> as the first child of <body>.
- The target: <main id="main-content" tabindex="-1"> where the id matches the fragment, and tabindex="-1" lets the element receive programmatic focus when activated.
Why tabindex="-1" on the target is not optional
This is the detail that breaks most skip links in production. When you activate an in-page link, the browser scrolls the target into view, but several browsers do NOT move keyboard focus to a non-interactive element like <main> unless it is focusable. Without tabindex="-1", focus stays on the (now scrolled-away) skip link, so the next Tab press resumes from the top of the page and the user is dumped right back into the navigation they tried to skip. Adding tabindex="-1" makes <main> a valid focus target so the keyboard position truly moves to the content.
Making the skip link visible on focus
A skip link is conventionally hidden until focused, so it doesn't disrupt the visual design, but it must become clearly visible when a keyboard user tabs to it. The trap to avoid is display:none or visibility:hidden, which removes the element from the tab order entirely, so it can never be focused and the skip link does nothing.
Use the clip pattern instead: position the link off-screen visually while keeping it in the accessibility tree and tab order, then reveal it on :focus.
- Hidden state: position:absolute with the standard 1px clip technique, so the link is out of view but still focusable.
- Visible state: a .skip-link:focus rule that brings it to a fixed, visible position at the top-left, for example top:0; left:0; with a solid background, padding, and a high z-index so it sits above the header.
A revealed skip link is itself a focusable control, so it must meet 2.4.7 Focus Visible (Level AA) and the contrast rules: at least 3:1 against adjacent colours for the focus indicator and 4.5:1 for the link text. Verify the colours with our contrast checker. This focus-reveal pattern is the same discipline you apply across all interactive elements.
Testing and common mistakes
You can verify both mechanisms in under a minute without any tooling: load the page, press Tab once, and confirm a visible "Skip to main content" link appears. Press Enter, then Tab again; focus should land on the first interactive element inside <main>, not back in the header. In a screen reader, open the landmarks list and confirm banner, navigation, main, and contentinfo are all present and uniquely named.
- Skip link present but pointing at a non-existent id, or at a heading with no tabindex, so focus silently fails to move.
- Multiple <main> elements, or <main> nested inside another landmark, which invalidates the main role.
- A skip link hidden with display:none so it never enters the tab order.
- Wrapping every link list in <nav>, flooding the landmarks menu and making it useless.
- A top-level <footer> placed inside <main>, so it never becomes contentinfo.
Automated tools catch the structural half of this well: missing main, duplicate unnamed landmarks, broken fragment targets. Run a free scan with AccessScan to flag landmark and bypass-block issues across your pages, then keep the manual Tab-key test in your release checklist. Our accessibility checklist folds 2.4.1 into a broader pre-launch list.