J3.03.3skip link destinationdesignresearch

After skipping, focus must actually land on the target

Aliases: skip target · fragment focus · in-page destination

What it is

After the skip link fires, keyboard focus must sit on the destination node for main content, and the next Tab must start there. Scrolling the viewport while focus stays on the skip link is not a successful skip: the next Tab returns to the next stop in the nav. The tax was not waived; the screen merely jumped.

The destination has to be able to receive focus. A non-focusable <main> often leaves focus on the original link or dumps it on body. Scroll position and focus position are different facts.

Why it happens

href="#main" historically scrolls the viewport. A non-interactive element without tabindex was not a focus target, so after activation focus remained on the skip link. The next Tab is “the next stop after skip” — the first item in the header — and the shortcut is short-circuited. Giving the destination tabindex="-1" (programmatically focusable, not inserted into the tab sequence) is the usual patch on that contract. Some user agents now move fragment focus to the target; do not assume every combination does.

A second failure: the id points at the wrong node, scrolling to a sidebar or an empty wrapper; or main content renders asynchronously after the jump, the anchor does not exist yet, focus has nowhere to go. If a single-page route destroys and rebuilds <main>, a jump to the old id hits empty.

Studying it

Activate skip, inspect document.activeElement immediately, Tab once, and see whether the landing is the first control in main or a link in the nav. Log three things: whether scroll happened, which node holds focus, where the next Tab goes. Watching scroll alone yields false positives.

Cover: fresh load, after one client-side route, a skeleton where main appears late. Anchor survival differs in those three moments.

Where it stops holding

The destination, when focused, need not draw a thick ring like a button — programmatic focus on <main> can interfere with reading. The container’s focus style may be quieter; focus must still be on that node. Multiple skip entries (skip nav, skip search) must each land on their own target, not all scroll to the top of the page. Print preview or an embedded reading view with no <main> needs an equivalent content container; do not point the jump at chrome that is no longer in the view.

Applying it

  • Give the main container a stable id and make it programmatically focusable (commonly tabindex="-1").
  • Point the skip link’s href at that id. After the jump, confirm activeElement is that container or the first meaningful control inside it.
  • If main renders asynchronously, wait until the target exists to finish the jump, or move focus onto the container when it appears.
  • How to check: activate skip, then Tab once. If focus is back in the header, the page only scrolled; the destination did not catch focus.

Related

  • Same group: J3.03.1 Repeated navigation needs a skip-in · J3.03.2 The skip link must become visible on focus
  • Nearby: J3.02 Focus order and focus traps · J2.08 Reading order · J2.14 Headings and landmarks
  • Search terms: skip target · tabindex="-1" · in-page fragment focus

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/J3.03.3