Source Code

<div class="demo">
  <div class="debug-toolbar">
    <button class="debug-toggle" id="debugToggle">Show tab order</button>
    <span class="debug-hint">Numbers appear in real DOM tab order, including a deliberately mis-ordered tabindex to demonstrate the problem this tool catches.</span>
  </div>

  <form class="sample-form" id="sampleForm">
    <div class="f-row">
      <label for="fFirst">First name</label>
      <input id="fFirst" type="text" tabindex="0" />
    </div>
    <div class="f-row">
      <label for="fLast">Last name</label>
      <input id="fLast" type="text" tabindex="3" />
    </div>
    <div class="f-row">
      <label for="fEmail">Email</label>
      <input id="fEmail" type="email" tabindex="2" />
    </div>
    <div class="f-row">
      <label for="fCountry">Country</label>
      <select id="fCountry" tabindex="0"><option>United States</option><option>Canada</option></select>
    </div>
    <div class="f-actions">
      <button type="button" class="btn ghost" tabindex="0">Cancel</button>
      <button type="submit" class="btn primary" tabindex="0">Submit</button>
    </div>
  </form>
</div>

Keyboard Focus Order Debugger — Visual Overlay Showing the REAL Tab Order

Keyboard Focus Order Debugger — Numbered Tab-Order Overlay · Dashboards · Plain HTML, CSS & JS · Live preview

What's included

Features

Computes the browser's actual two-phase tab-order algorithm (positive tabindex first, ascending, then document order) rather than assuming DOM order
Visually flags any element whose real tab position disagrees with its plain DOM position, in a distinct red badge color
Numbered badges positioned inline with each element's own natural layout, requiring no manual coordinate or resize tracking
Includes a deliberately mis-ordered tabindex in the sample form to demonstrate exactly the kind of bug the tool catches
Toggleable overlay that fully removes itself (and every badge it created) when turned off
Zero dependencies — pure DOM query and comparison logic, usable as a real ad hoc debugging tool dropped into any page
Directly demonstrates why positive tabindex values are widely discouraged in accessibility guidance, with a visible before/after

About this UI Snippet

Focus Order Debugger — Visualizing the Tab Order Browsers Actually Use

Screenshot of the Keyboard Focus Order Debugger — Numbered Tab-Order Overlay snippet rendered live

A form's visual layout and its keyboard tab order are *usually* the same sequence, but not always — and the moment they diverge, keyboard users experience a genuinely disorienting bug that's nearly invisible to a developer testing only with a mouse. This snippet builds a small diagnostic overlay that computes and numbers the browser's *actual* tab order, not an assumption based on how the markup is written top to bottom.

The tab order algorithm most developers get wrong

The browser's real keyboard tab order isn't simply "DOM document order." Any element with a positive tabindex value (tabindex="1", tabindex="2", etc.) is visited *first*, in ascending numeric order — before *any* element with tabindex="0" or no tabindex attribute at all, which are then visited in plain document order among themselves. computeRealTabOrder() reproduces this exact two-phase algorithm: it filters out and sorts every positive-tabindex element numerically first, then appends every remaining element in its natural document order — which is the actual spec-defined behavior, not a simplification of it.

Why the demo form deliberately includes a "wrong" tabindex

The last name field in the sample form has tabindex="3" while the email field below it has tabindex="2" — meaning a keyboard user tabbing through the form actually lands on email *before* last name, even though last name appears visually first. This is exactly the kind of bug that's easy to introduce accidentally (often from copy-pasted markup, or tabindex values added defensively without a full audit) and is invisible unless someone is specifically testing with a keyboard.

Red versus green badges — comparing the two orderings directly

For every focusable element, the code compares its position in the *real* computed tab order against its position in *plain DOM order* — if they match, the badge renders green ("this element's tab position matches where it visually and structurally sits"); if they differ, it renders red ("a positive tabindex has pulled this element out of its natural sequence"). This turns an abstract ordering bug into an immediately obvious visual signal, without a developer needing to manually trace through tabindex values by hand.

Badges are positioned per-element, not as one absolute overlay

Rather than computing one absolute-positioned layer that has to track every element's coordinates and stay in sync during resize or reflow, each numbered badge is appended directly into its target element's own containing .f-row (with position: relative ensured on that container), positioned with a small negative offset. This means the badges inherit the form's own natural layout and reflow behavior for free — no manual coordinate tracking or resize-listener bookkeeping required.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI assistant to walk through the browser's actual two-phase tab-order algorithm in detail — why positive tabindex values are visited first and in what order — and to explain why this makes positive tabindex values broadly discouraged in accessibility best practices. It's also worth asking for a version that also flags elements that are focusable but visually hidden (a separate, equally real accessibility bug), or one that overlays the whole page rather than a single container, dynamically re-scanning as the DOM changes.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a keyboard focus-order debugging overlay in HTML, CSS, and vanilla JavaScript — no external library.

Requirements:
- A sample form with at least five focusable elements (inputs, a select, and buttons), where at least one element has an explicit positive tabindex value that is deliberately out of sequence relative to where it appears in the markup, specifically to demonstrate the bug this tool should catch.
- A toggle button that, when activated, computes the ACTUAL browser keyboard tab order — correctly implementing the real two-phase algorithm: every element with a positive tabindex value visited first in ascending numeric order, followed by every tabindex="0" or tabindex-less element in plain document order — rather than assuming tab order simply matches document order.
- Render a small numbered badge on every focusable element showing its position in that real computed tab order.
- For each element, separately compare its position in the real tab order against its position in plain DOM order, and give badges a distinctly different color (e.g. red vs. green) depending on whether those two positions match or differ, so a developer can immediately spot which specific elements have been pulled out of natural sequence by a tabindex value.
- Position each badge relative to its own target element's layout (not as one separately-tracked absolute overlay), so it stays correctly placed without needing manual coordinate tracking.
- Toggling the debugger off must fully remove every badge it created, leaving no leftover DOM elements behind.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Click "Show tab order"Numbered badges appear on every focusable element in the form, reflecting the browser's actual keyboard tab sequence — not just their visual top-to-bottom order.
  2. 2
    Look for red badgesA red badge means that element's real tab-order position differs from its plain DOM position — usually caused by a positive tabindex value pulling it out of sequence.
  3. 3
    Tab through the form manually to confirmClick the first field, then press Tab repeatedly — the order you land on fields in matches exactly the numbers shown by the overlay.
  4. 4
    Fix a flagged elementRemove its explicit positive tabindex (or set it to "0") so it participates in natural document order instead of being artificially reordered.
  5. 5
    Click "Hide tab order"Removes all badges cleanly, since each one was tracked in an array specifically so it could be fully cleaned up later.

Real-world uses

Common Use Cases

A11Y
Accessibility auditing during development
Quickly spot keyboard tab-order bugs on any form or interactive layout without manually tabbing through and mentally tracking the sequence.
QA
QA and pre-release accessibility checks
A lightweight visual tool for QA engineers to verify tab order matches visual order before shipping a new form or page.
DEBUG
Debugging reported keyboard-navigation complaints
When a user reports "tab order feels wrong" on a page, this overlay turns a vague complaint into a precise, visible diagnosis.
TRAINING
Teaching the real tabindex algorithm
A concrete, visual way to demonstrate to other developers exactly why positive tabindex values are risky and how the browser actually orders focus.
Related: Loyalty Program Tier Progress
See the Loyalty Program Tier Progress for a related dashboards pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

No — any element with a positive tabindex value is visited first, in ascending numeric order, before any tabindex="0" or tabindex-less element (which are then visited in plain document order). This two-phase algorithm is exactly what computeRealTabOrder() reproduces, rather than assuming DOM order is always correct.

It's deliberately included to demonstrate the bug this tool is designed to catch — the last name field (tabindex="3") appears visually before the email field (tabindex="2"), but a keyboard user actually tabs to email first, which the red badge on last name makes immediately visible.

It means that element's position in the real, browser-computed tab order differs from its position in plain document order — almost always because a positive tabindex value has pulled it earlier or later than where it naturally sits in the markup.

Remove its positive tabindex attribute entirely, or change it to tabindex="0" — either lets the element participate in natural document-order tabbing instead of being artificially prioritized ahead of (or pushed behind) elements around it.

Appending each badge directly into its target's own container lets it inherit that container's natural layout and reflow automatically — no need to track element coordinates manually or recompute positions on window resize, which a single absolute-overlay approach would require.

Yes — FOCUSABLE_SELECTOR matches any standard focusable element (links, buttons, inputs, selects, textareas, and anything with an explicit tabindex), so the same logic works on any container, not just a <form>.