Lab 11
Tab Walk
Tab order and focus order visualizer (WCAG 2.4.3 and 2.4.11)
The Reading Order lab shows that the layout and the DOM can disagree. This lab shows what that does to someone pressing Tab: numbered stops drawn over a page, and the four things that scramble them.
Before you start
Press Tab on any page and focus moves to the next focusable element in the order the browser keeps. That order is the DOM order, with one exception: any element with a positive tabindex goes first, lowest number first. CSS cannot change the order. Hiding can remove a stop, but only some kinds of hiding.
The lab below draws the number of each Tab stop on a small shop page. Every control is real. You can press Tab inside the page yourself, or press the walk button and let the lab do it while it counts. The count matters: the number of focusable elements in the markup and the number of stops a walk actually visits can differ, because menus and disclosures add stops while the walk is running. When they differ, trust the walk.
Two more scenarios follow. A sticky header that covers the focused field, which WCAG 2.2 calls focus not obscured (2.4.11), with the one CSS line that fixes it. And a dialog, with the three things it has to do with focus: put it inside, keep it inside, and give it back.
The lab
Start by pressing the walk button and watching the numbers. Then tick "Reorder the cards with CSS only" and walk again: the cards move, the numbers do not. Tick "Reorder in the DOM" instead and they move together.
What you just learned
- Tab order is DOM order. CSS
ordermoved the cards on screen and left the numbers where they were, so focus jumps backwards across the row. Moving the card in the DOM moved both. That is rule AW-ORDER-001 in the ruleset. - A positive tabindex jumps the queue.
tabindex="5"made the Buy button stop 1, ahead of the header links, and everything else fell into line after it. That is AW-KEY-002, and the fix is never a bigger number. - tabindex="0" on a container is a stop that does nothing. Three extra presses to get through the cards, and nothing happens at any of them.
- Hiding is three different things.
display: noneandvisibility: hiddenremove the stop.aria-hidden="true"does not. The link is still on screen and still in the Tab sequence; it has only been hidden from the accessibility tree, so a screen reader user lands on silence. That is AW-ARIA-002. - The walk count beats the markup count. The "More ways to pay" disclosure opens when it gets focus and adds three links. A static count misses them. A real walk finds them. The same gap turns up on real pages at a much larger scale.
- Just into view is under the header. When focus moves to a field above the visible area, the page scrolls only as far as it must, and that puts the field behind a sticky header. The lab scrolls the minimum distance, which some browsers do on Tab; others centre the field, and a tall enough header still covers it.
scroll-padding-topon the scrolling container tells every browser where the real top is. - A dialog owes focus three things. Put it inside on open, keep Tab inside while it is open, and return it to the opener on close. Untick any one and read where focus ends up. That is AW-KEY-004.
Embed this lab
Host the Tab Walk on your own page with one element and one script. It runs entirely in the visitor's browser, sends nothing back, and adds a small credit link.
<div data-a11y-world-lab="tab-walk"></div>
<script src="https://a11y.world/embed.js" async></script>
The sample page's links go nowhere. Its controls are real, so your page's global styles for buttons and inputs apply to them.
Related notes
-
Tab order is a promise the DOM makes
The Tab key follows the HTML, not the layout. CSS cannot change that order, a positive tabindex hijacks it, and aria-hidden does not remove a stop. One real walk found 162 stops where a list of the markup said 64. Here is why, and how to check.
-
The sticky header that eats your focus
Shift+Tab back up a form and the field you land on slides under the sticky header. The browser scrolled just far enough, and just far enough is behind the bar. WCAG 2.2 calls it focus not obscured. One CSS property fixes it.
-
Where focus goes when a dialog opens
A dialog owes a keyboard user three things. Put focus inside it on open. Keep Tab inside while it is open. Give focus back to the opener on close. Miss any one and the reader is lost behind the dialog or dropped at the top of the page.
-
The focus ring is the interface
For anyone who moves through a page without a mouse, the focus ring is the cursor. Here is what a great one looks like and why most of them fail.
-
Hover is a state most people do not have
Touch, keyboard, switch, and voice never hover. A menu, tooltip, or button that appears only on hover does not exist for them.
-
Skip links people actually find
A skip link that is first in the tab order, visible the moment it has focus, and labeled for where it goes. Most skip links fail at least one of those.
-
Why agents miss focus states
Static analysis cannot see a focus ring. Here is the three-step procedure an agent can run instead, and the one CSS pattern that passes everywhere.
-
Why your focus ring vanishes in dark mode
A ring designed on a white mockup is a coin toss once the page can be dark. The fix is not a darker ring. It is a second tone.