Accessibility pattern · Navigation

Skip links

The first Tab on the page reaches a link that jumps past the header, so nobody has to press Tab through every menu item to reach the content. The links stay out of sight until one has focus, and each target can take focus, so the next Tab carries on from where the jump landed.

WCAG criteria
6
Keyboard rules
3
Checked with
axe, keyboard and the inspector

Live demo

Try it

Use it with a mouse, a keyboard or a screen reader. The inspector beside it shows what the browser tells assistive technology as you go: focus, state changes and announcements.

The demo works without JavaScript only as far as its HTML does; the inspector needs JavaScript.

Keyboard

Keys it answers to

Every action works without a pointer.

KeyWhat it does
TabFrom the top of the page, reveals the skip links on the first press; the next press moves to the second link, then on into the header.
EnterFollows the focused skip link: focus moves to the main content, or straight into the search field.
Tab or ShiftTabAfter a jump, moves on from the target, not from the top of the page.

Screen readers

What it announces

Written from the roles, names and states in the markup.

WhenExpected announcement
The first Tab reaches the skip linksSkip to main content, link
Enter follows itFestive edit, region
Tab after the jumpChanderi cotton saree, link
Enter on Skip to searchSearch the shop, search edit text

These are expected announcements, not recordings. Wording and order differ between screen readers and browsers.

Code

Copy the code

The exact files this demo runs on. The styles are served with a prefix that keeps this site's own styles out of the demo; what you copy is the original.

The markup

<div class="ap-skip-links" data-ap-skip-links>
  <p class="ap-skip-links__hint">Press <kbd>Tab</kbd> from the demo settings above. The shop's first stop is a pair of skip links.</p>

  <div class="ap-skip-links__page">
    <div class="ap-skip-links__bar">
      <a class="ap-skip-links__link" href="#skip-main">
        <svg class="ap-skip-links__arrow" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M6 13l6 6 6-6"/></svg>
        Skip to main content
      </a>
      <a class="ap-skip-links__link" href="#skip-search">
        <svg class="ap-skip-links__arrow" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.5"/><path d="m16 16 4 4"/></svg>
        Skip to search
      </a>
    </div>

    <header class="ap-skip-links__header">
      <div class="ap-skip-links__top">
        <a class="ap-skip-links__logo" href="#skip-home">
          <svg class="ap-skip-links__mark" viewBox="0 0 32 32" aria-hidden="true" focusable="false"><rect x="2" y="2" width="28" height="28" rx="9"/><path d="M10 22V10l12 12V10"/></svg>
          <span>Nila</span>
        </a>
        <search class="ap-skip-links__search">
          <label class="ap-skip-links__sr" for="skip-search">Search the shop</label>
          <svg class="ap-skip-links__glass" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.5"/><path d="m16 16 4 4"/></svg>
          <input class="ap-skip-links__input" id="skip-search" type="search" placeholder="Search" autocomplete="off" />
        </search>
      </div>
      <nav class="ap-skip-links__nav" aria-label="Main">
        <ul class="ap-skip-links__menu">
          <li><a href="#skip-new">New in</a></li>
          <li><a href="#skip-sarees">Sarees</a></li>
          <li><a href="#skip-kurtas">Kurtas</a></li>
          <li><a href="#skip-linen">Home linen</a></li>
          <li><a href="#skip-sale">Sale</a></li>
        </ul>
      </nav>
    </header>

    <section class="ap-skip-links__main" id="skip-main" tabindex="-1" aria-labelledby="skip-main-name">
      <h3 class="ap-skip-links__name" id="skip-main-name">Festive edit</h3>
      <p class="ap-skip-links__lead">Handwoven pieces for Diwali, made in small batches by weavers in Chanderi, Kanchipuram and Bhagalpur.</p>
      <ul class="ap-skip-links__products">
        <li class="ap-skip-links__product">
          <span class="ap-skip-links__swatch" aria-hidden="true"></span>
          <a class="ap-skip-links__product-link" href="#skip-chanderi">Chanderi cotton saree</a>
          <p class="ap-skip-links__price">₹4,200</p>
        </li>
        <li class="ap-skip-links__product">
          <span class="ap-skip-links__swatch" aria-hidden="true"></span>
          <a class="ap-skip-links__product-link" href="#skip-kanjivaram">Kanjivaram silk dupatta</a>
          <p class="ap-skip-links__price">₹6,800</p>
        </li>
        <li class="ap-skip-links__product">
          <span class="ap-skip-links__swatch" aria-hidden="true"></span>
          <a class="ap-skip-links__product-link" href="#skip-tussar">Bhagalpur tussar stole</a>
          <p class="ap-skip-links__price">₹2,350</p>
        </li>
      </ul>
    </section>
  </div>
</div>

WCAG 2.2

What it meets

The success criteria this pattern takes care of, and how.

  • 2.4.1 Bypass Blocks Level A

    The skip link is the first stop on the page and lands past the header's seven stops: the logo, five links and the search field.

  • 2.1.1 Keyboard Level A

    Following a skip link is an ordinary link activation, so Enter works with every browser and screen reader.

  • 2.4.3 Focus Order Level A

    Focus moves to the target itself, so the next Tab continues from the content instead of going back into the header.

  • 2.4.4 Link Purpose (In Context) Level A

    Each link says where it goes, Skip to main content and Skip to search, with no need for context.

  • 2.4.7 Focus Visible Level AA

    A skip link is drawn in full the moment it has focus, and the target shows a ring where focus landed.

  • 2.4.11 Focus Not Obscured (Minimum) Level AA

    The revealed links float over the header, and they hide again as soon as focus moves on, so they never cover the element that has focus.

Usage

When to use it

Use it

  • Any page with a header or navigation that repeats on every page.
  • Pages with a long toolbar or filter panel before the results.

Use something else

  • As a stand-in for headings and landmarks: screen reader users move by those, so the page needs both.
  • A long list of links to every section: that is a table of contents, and it belongs on the page where everyone can see it.

Common failures

How it usually goes wrong

  • Hidden for good with display: none

    display: none or visibility: hidden takes the link out of the Tab order too, so nobody can use it. Clip it instead, and show it on focus.

  • A target that cannot take focus

    Without tabindex="-1" on the target, some browsers scroll to it but leave focus behind, and the next Tab goes straight back into the header.

  • Not the first stop

    A cookie banner, a logo or a language picker before the skip link makes people tab past the very things it was meant to skip.

  • Revealed under something else

    A skip link that appears beneath a sticky header or a banner has focus but cannot be seen, which leaves sighted keyboard users lost.

  • A link to an id that is gone

    Redesigns rename the content's id, and the skip link silently stops working. Check it whenever the layout changes.

  • A ring around the page on every click

    tabindex="-1" lets a click focus the target too. Style :focus-visible, not :focus, so mouse users do not see the whole page outlined.

Notes

Building it

  • Point the main skip link at your main element. The demo targets a section, because the shop sits inside this page, which already has its one main landmark.
  • The links work without the script: following an in-page link moves focus to a target with tabindex="-1". The script moves focus itself so the address bar and the Back button are left alone, which also keeps hash routers in single-page apps out of it.
  • Hide the links with a clip, not by moving them off screen, so the browser never scrolls sideways to reach a focused one.
  • If your header is sticky, give each target scroll-margin-top, so a jump does not land underneath it.
  • Two links are plenty. Landmarks and headings take care of the rest for screen reader users.

Sources: WCAG technique G1: a link to the main content · Understanding 2.4.1 Bypass Blocks

Checked with axe in light and dark themes, at desktop and phone widths, and by keyboard. Not yet tested with every screen reader and browser pair. Report a correction