Ever tabbed through a page and wondered why your cursor suddenly jumps to a seemingly random button or input? Or why sometimes the first form field is focused automatically, and other times you need to click or tab your way in? As a developer, your go-to tools are usually tabindex and the autofocus attribute. But there’s a whole focus management engine humming quietly inside every browser that decides where keyboard focus lands, how it moves, and how it interacts with your DOM.
I ran into this while debugging a tricky accessibility issue: a modal would open, but the keyboard focus landed outside the modal, confusing screen reader users and keyboard navigators. I had set tabindex on the modal and used autofocus on the first input, but it still misbehaved. Why?
Turns out, browsers have a complex set of rules and heuristics for managing focus under the hood. Let me walk you through what I learned looking past tabindex and autofocus, and how browsers really decide focus.
When a page loads, what gets focus?
You might think the first element with autofocus gets focus. Usually true, but not the whole story.
Browsers follow an internal focus algorithm roughly like this:
- If there’s an element with the
autofocus attribute and it’s focusable, focus it.
- Otherwise, focus the first focusable element in the document’s tab order.
- If none exist, focus the
<body> or nothing.
But what counts as "focusable"? And what defines the "tab order"?
What’s focusable?
- Native interactive elements like
<input>, <button>, <select>, <a href>.
- Elements with
tabindex >= 0.
- Elements with
contenteditable.
But not all tabindex are equal. tabindex="-1" makes an element programmatically focusable but removes it from the sequential keyboard navigation order.
Tab order
The tab order is the linear sequence browsers follow when you press Tab. It’s mostly:
- Elements with a positive tabindex, in ascending order.
- Elements with no tabindex (or tabindex=0), in DOM order.
Positive tabindex values > 0 are discouraged but still respected by browsers, which can lead to confusing focus orders.
Keyboard navigation: How does focus move?
When you hit Tab or Shift+Tab, browsers shift focus according to the tab order. But under the hood, it’s an algorithm that:
- Collects all focusable elements.
- Sorts them by tabindex (positive first, ascending), then DOM order.
- Moves focus forward or backward.
Here’s a gotcha: if you mix positive tabindex values, your tab order might jump around unexpectedly.
For example:
<button>First</button>
<input tabindex="2">Second</input>
<input tabindex="1">Third</input>
<button>Fourth</button>
Pressing Tab will focus elements in this order: Third (tabindex=1), Second (tabindex=2), then First and Fourth (default tabindex=0, DOM order).
So positive tabindex overrides DOM order entirely.
What about autofocus inside modals or dynamic UI?
The autofocus attribute only works during page load, not when you dynamically add elements or show modals.
To focus elements in modals:
- You must call
element.focus() programmatically when the modal opens.
- Make sure the element is focusable (visible, not disabled).
- Trap focus inside the modal, so Tab and Shift+Tab don’t escape.
Browsers don’t do this for you. You have to manage focus manually here.
Browsers’ internal focus management quirks
Even with all this, browsers have subtle differences:
- Some browsers skip disabled elements during tabbing; others might include them.
- The presence of shadow DOM or iframes affects focus navigation.
- Some browsers restore focus to the last focused element on navigation back/forward.
I found that relying purely on tabindex and autofocus isn’t enough for robust focus management, especially in complex apps with dynamic UI.
Practical tips from under the hood
-
Avoid positive tabindex: Stick to tabindex=0 or -1. Positive values mess with the natural DOM order and confuse users.
-
Use autofocus sparingly: It works only on initial load. For modals and dynamic content, use element.focus() in JS.
-
Make elements truly focusable: Invisible elements, or those with display:none or visibility:hidden won’t get focus.
-
Trap focus in modals: Use focus traps to cycle focus inside overlays. Libraries like focus-trap can help.
-
Test keyboard navigation thoroughly: Try tabbing forward and backward, test with screen readers.
Why all this matters
Good focus management isn’t just about keyboard users. It also helps screen reader users orient themselves, improves form usability, and prevents confusing UX where focus disappears or jumps unexpectedly.
Browser focus management is a mix of default heuristics, platform quirks, and your app’s DOM structure. Understanding what happens under the hood lets you control focus predictably and fix bugs that at first seem mysterious.
Next time you see strange keyboard navigation or focus bugs, remember: it’s rarely just about tabindex or autofocus. The browser is running a whole focus algorithm behind the scenes. Knowing that algorithm helps you debug, build better accessibility, and create smoother UX.