Should focus order follow the visual layout or the DOM when they differ?
On this page
Focus should follow the order users perceive on screen, and when the DOM order and the visual order disagree, the right fix is almost always to bring the markup back in line with the visual flow rather than papering over the gap with overrides. A keyboard user does not see your source. They press Tab and expect the highlight to march through the page the way their eyes would, top to bottom, left to right, in reading order. When the tab sequence jumps from the header to the footer and back up to a sidebar because the HTML was authored in a different order than it renders, the experience becomes unpredictable and disorienting. The cleanest answer is to make the two orders match at the source.
The reason source order matters is that the browser builds the tab sequence from the document order of focusable elements, not from where CSS happens to paint them. Flexbox and Grid let you visually reposition elements with properties like order, row-reverse, or explicit grid placement without touching the underlying HTML. That power is exactly where the trap lives. You can drag a “Continue” button to the visual bottom while it still sits early in the DOM, so a keyboard user reaches it long before the fields above it. The visual layer lies about sequence, and assistive technology reads the truth underneath.
A concrete case: a designer builds a pricing section with three plan columns using CSS Grid, and to highlight the middle “recommended” plan, they place it visually in the center but author it first in the markup so a separate badge can hang off it. On screen the order reads left, center, right. By keyboard the order is center, left, right. The user tabs into the recommended plan, then back to the cheap plan, then to the expensive one, with the focus ring leaping across the screen in a pattern that maps to nothing they can see. Reordering the three articles in the HTML to left, center, right and styling the highlight separately makes focus and vision agree again.
What sits outside this is the tabindex attribute, which is the wrong tool for this job in two of its three forms. A positive tabindex (1 or higher) forces an element to the front of the tab sequence and creates exactly the brittle, leapfrogging behavior you are trying to avoid, so it should be treated as off-limits for ordinary layout. The legitimate uses are tabindex="0" to make a genuinely custom interactive element focusable in its natural document position, and tabindex="-1" to allow programmatic focus (such as moving focus to a heading after a route change) without inserting the element into the Tab cycle. None of these should be used to manufacture an order that the DOM could simply express directly.
When you find a focus order that fights the visual flow, resolve it by reordering the markup so document order matches reading order, then let the tab sequence fall out naturally. Reserve CSS reordering for cases where the visual and source orders still agree, and reach for tabindex only to make custom widgets focusable or to manage focus deliberately, never to rescue a layout you reversed in CSS. Tab through every page yourself and watch the focus ring: if it ever jumps somewhere your eye would not go next, fix the source, not the symptom.