Lesson 01 · Keyboard · Breakdown
What was hiding in there.
The Northwind page held five barriers. Each one is shown below with the control, what it does to a keyboard user, and the one change that fixes it. How many did you find?
01 "Start free trial" cannot be reached
You notice: Tab never lands on the main button. The most important action on the page is invisible to the keyboard.
Why: it is styled like a button but it is a <div>, which is not in the tab order and is not announced as a control. Swap it for a real <button>.
<div class="btn primary">Start free trial</div><button type="button" class="btn primary">Start free trial</button>WCAG 2.1.1 Keyboard (Level A)
02 "Watch demo" is a link with no destination
You notice: the action next to the trial button is also skipped by Tab, even though it looks like a normal link.
Why: it is an <a> with a click handler but no href. An anchor without an href is not focusable. Use a <button> for an action, or give the link a real href.
<a onclick="playDemo()">Watch demo</a><button type="button" onclick="playDemo()">Watch demo</button>WCAG 2.1.1 Keyboard (Level A)
03 The billing toggle hides focus
You notice: tabbing onto the Monthly / Yearly switch, nothing changes on screen. You cannot tell which option is focused.
Why: the focus outline was removed in CSS. The buttons still take focus, but with no visible ring a keyboard user is choosing blind. Restore a :focus-visible outline.
.toggle button:focus {
outline: none;
}.toggle button:focus-visible {
outline: 3px solid #1364ff;
outline-offset: 3px;
}WCAG 2.4.7 Focus Visible (Level AA)
04 The currency menu will not open
You notice: the currency control never takes focus, and nothing you press opens it. The options inside are unreachable.
Why: the trigger is a <div> wired to click only, and the items are plain <div>s. A real menu needs a <button> trigger with aria-expanded, plus items that respond to the arrow keys and Esc.
<div onclick="toggle()">USD</div>
<ul hidden>
<li><div>EUR, Euro</div></li>
</ul><button aria-haspopup="true"
aria-expanded="false">USD</button>
<ul role="menu" hidden>
<li role="none"><button role="menuitem">EUR, Euro</button></li>
</ul>WCAG 2.1.1 Keyboard (Level A) and 4.1.2 Name, Role, Value (Level A)
05 The invite form tabs out of order
You notice: the fields read Name, then Email, then the button, but Tab visits Email first, then the button, then back up to Name.
Why: positive tabindex values override the natural order. Any value above 0 is pulled to the front of the sequence. Remove them and let source order do the work.
<input name="name" tabindex="3">
<input name="email" tabindex="1">
<button type="submit" tabindex="2"><input name="name">
<input name="email">
<button type="submit">WCAG 2.4.3 Focus Order (Level A)
Now see it done right
The same Northwind page, rebuilt so every one of these works with a keyboard.