2.4.3 Focus Order
Level: A | Principle: Operable | Since: WCAG 2.0 | Automation: Manual
What This Means
When users navigate a page with a keyboard (Tab / Shift+Tab), the focus order must be logical and meaningful. Focus should follow the visual reading order — left to right, top to bottom in LTR languages — so that the sequence of interactive elements makes sense. A confusing focus order disorients users who cannot see or easily scan the entire page.
Who This Affects
- Keyboard-only users — rely on Tab order to understand page structure and reach controls
- Screen reader users — perceive the page linearly, so a jumbled focus sequence breaks comprehension
- Low-vision users — may follow the focus indicator; if it jumps erratically, they lose context
- Switch device users — sequential access means every out-of-order stop wastes time and effort
Common Pitfalls
1. Using positive tabindex values
tabindex values greater than 0 force an element to the front of the tab queue, overriding the natural DOM order. This almost always creates a confusing sequence.
<!-- Bad: positive tabindex creates unpredictable order -->
<input tabindex="3" placeholder="Last name" />
<input tabindex="1" placeholder="Email" />
<input tabindex="2" placeholder="First name" />
<!-- Good: rely on DOM order, no positive tabindex -->
<input placeholder="First name" />
<input placeholder="Last name" />
<input placeholder="Email" />
2. Visual order doesn't match DOM order
CSS flexbox or grid reordering can make the visual layout differ from the DOM order, which is what keyboard focus follows.
/* Bad: visual order differs from DOM order */
.container {
display: flex;
flex-direction: row-reverse;
}
/* Good: if you reorder visually, reorder the DOM to match */
3. Dynamically inserted content placed far from the trigger
<!-- Bad: button at top, error message inserted at bottom -->
<button onclick="validate()">Submit</button>
<!-- ...many elements... -->
<div id="error-msg"></div>
<!-- Good: feedback appears near the trigger -->
<button onclick="validate()">Submit</button>
<div id="error-msg" role="alert"></div>
4. Modal focus not trapped
When a modal opens, focus should move into the modal and stay trapped there until it closes. Otherwise Tab escapes into the background page.
How to Fix
Let DOM order drive focus order
Arrange your HTML source in the logical reading sequence. Avoid CSS reordering that conflicts with DOM order.
<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
<h1>Welcome</h1>
<form>
<label for="name">Name</label>
<input id="name" type="text" />
<label for="email">Email</label>
<input id="email" type="email" />
<button type="submit">Send</button>
</form>
</main>
Use tabindex correctly
| Value | Meaning |
|-------|---------|
| tabindex="0" | Element is focusable in DOM order — safe to use |
| tabindex="-1" | Focusable programmatically but not via Tab — safe for focus management |
| tabindex="1" or higher | Forces element to front of tab order — avoid |
Trap focus in modals
dialog.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
const focusable = dialog.querySelectorAll(
'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
How to Test
- Starting from the top of the page, press Tab repeatedly and watch the focus indicator move through interactive elements.
- Verify focus moves in a logical sequence that matches the visual layout: left to right, top to bottom (in LTR pages).
- Open DevTools and search for any elements with
tabindexvalues greater than 0, which force unnatural focus order. - Open a modal or dialog and confirm focus is trapped inside it (Tab cycles through modal controls without escaping to the background page).
- Check that dynamically inserted content (error messages, popups) appears near the element that triggered it in the focus order.
- Pass: Focus moves in a logical, predictable sequence matching the visual layout, and modals properly trap focus.
- Fail: Focus jumps erratically, skips elements, or moves in an order that contradicts the visual layout.
axe-core Rules
| Rule | What It Checks |
|------|---------------|
| tabindex | No element has a tabindex value greater than 0 |
Tools
Test this criterion with the Focus Order Visualizer.