CSS reading-flow: Tab order that matches the layout
Match tab order to visual order without reordering the DOM
Flex reverse and grid areas often put focusable items in a different order than the DOM. reading-flow makes tab and speech order follow the visual layout without shuffling markup or abusing tabindex.
The old hack vs the modern fix
View demo/* visual order via flex reverse, tab order fixed by reshuffling markup */
.nav {
display: flex;
gap: 1rem;
}
/* HTML rewritten per breakpoint, or tabindex="1/2/3" on each link */.nav {
display: flex;
flex-direction: row-reverse;
reading-flow: flex-visual;
gap: 1rem;
}
/* tab order follows what you see, not DOM reverse */Reading flow browser support
reading-flow ships in Chrome and Edge 137+. Firefox and Safari have no support yet. Keep DOM source order logical so unsupported browsers still get a usable tab path.
Live demo
Why the modern way wins
Keep sensible markup
Leave the DOM in a logical source order. Change how keyboard and speech travel through the visual layout.
Flex and grid modes
flex-visual, flex-flow, grid-rows, grid-columns, and grid-order each map reading to a layout model.
Fine tune with reading-order
On children, reading-order puts items into ordinal groups when reading-flow: source-order is set on the container.
- Old Approach
- Reorder DOM or tabindex
- Fragile across breakpoints
- Modern Approach
- reading-flow
- Visual order for focus and speech
How it works
By default, tab order and screen reader order follow the DOM. Visual tools like flex-direction: row-reverse or grid-area can make that feel wrong: you see Item 3 first, but Tab still lands on Item 1.
reading-flow: flex-visual on a flex container makes sequential navigation follow the visual order, including writing mode. flex-flow follows the flex flow direction instead. Grid gets grid-rows, grid-columns, and grid-order.
Positive tabindex values are ignored inside a reading flow container. That is intentional. Prefer reading-flow and reading-order over tabindex greater than zero. Firefox and Safari do not support this yet, so keep DOM order sensible as the baseline experience.