How to Use Tabindex for Better Keyboard Navigation: Complete Guide (2026)

Saar Twito9 min read
Saar Twito
Saar TwitoFounder & SEO Engineer

Hi, I'm Saar - a software engineer, SEO specialist, and lecturer who loves building tools and teaching tech.

View author profile →

What Is Tabindex?

The tabindex attribute controls whether — and in what order — an HTML element receives keyboard focus when a user presses Tab. Only three values are meaningful: tabindex="0" adds an element to the natural Tab order, tabindex="-1" makes it programmatically focusable but skipped by Tab, and any positive value (1, 2, …) overrides DOM order and is almost always a bug.

Key Facts (TL;DR)

  • tabindex="0": element is focusable in normal DOM order — use on custom interactive widgets like <div role="button">.
  • tabindex="-1": programmatically focusable via .focus(), skipped by Tab — use for skip-link targets, modal containers, error summaries.
  • tabindex="1" or higher: manually overrides Tab order. Almost always wrong. Violates WCAG 2.4.3 Focus Order (Level A) in most cases.
  • WCAG criteria: SC 2.1.1 Keyboard (A), SC 2.4.3 Focus Order (A), SC 2.4.7 Focus Visible (AA).
  • Audit threshold: automated accessibility tooling flags any element with tabindex >= 1 as a defect.
  • Business impact: the WebAIM 2024 Million report found 96.3% of homepages had detectable WCAG 2 failures — broken Tab order is one of the most common, and it directly blocks roughly 1 in 4 users who rely on keyboard or assistive tech (CDC disability data, 2024).

Think of tabindex like seat numbers at a theatre. With no numbers, people naturally fill rows in order (DOM order — the right outcome). Add tabindex="0" and an extra chair joins the row. Add tabindex="1", "2", "3"and you've told three specific guests to sit first regardless of where they are — everyone else now starts after them, and any new chair you add throws the whole numbering out.

Why Tabindex Matters for Accessibility

Keyboard navigation isn't a niche concern. It's how users with motor impairments, blind users on screen readers, power users, and anyone with a temporarily injured hand interact with your site. tabindex is the attribute that decides whether they can use it at all.

  • WCAG 2.1.1 Keyboard (Level A): every interactive element must be operable through a keyboard interface. A custom <div> with a click handler and no tabindex silently excludes every keyboard user.
  • WCAG 2.4.3 Focus Order (Level A): focus order must preserve meaning and operability. Positive tabindex values reorder elements in a way that almost always conflicts with the visual reading order — a direct failure.
  • WCAG 2.4.7 Focus Visible (Level AA): the focus indicator must be visible. tabindex="-1" can hide elements from the natural sequence; if you focus them programmatically, you also need to make the focus ring visible.
  • Screen-reader navigation: screen readers usually traverse content in DOM order regardless of tabindex. Positive values create a mismatch where keyboard-only users land somewhere different from screen-reader users — a deeply confusing experience.
  • Maintenance cost: a form with tabindex="1" through "7" needs renumbering every time someone adds, removes, or reorders a field. DOM source order needs nothing.

How the Three Tabindex Values Actually Work

Most tabindex bugs come from misunderstanding what each value does. Here is the precise behaviour the browser applies.

tabindex="0" — Add to Natural Order

Adds a non-focusable element (like <div>, <span>, or <li>) to the keyboard Tab sequence at its DOM position. Use it whenever you build a custom interactive widget that the browser doesn't already make focusable. Don't add it to elements that are already focusable (like <button> or <a href>) — it is redundant and only adds noise.

tabindex="-1" — Programmatic Focus Only

Removes the element from the Tab sequence but allows JavaScript to call element.focus() on it. Use for: skip-link targets like <main id="main" tabindex="-1">, modal dialog containers that should receive focus on open, error summaries you want to scroll into view after form validation, and route-change focus targets in single-page apps.

tabindex="1" and Higher — Almost Always a Bug

Forces the element to come first (or n-th) in Tab order, ahead of every element with tabindex="0" or natural focusability. Three reasons it breaks accessibility: (1) it conflicts with visual and source order, violating WCAG 2.4.3; (2) once a user finishes the positive-tabindex group, focus jumps back to the start of natural order — confusing and disorienting; (3) screen readers ignore it and walk DOM order anyway, so keyboard-only and screen-reader users get different journeys.

<!-- BAD: positive tabindex creates a manual queue
     that breaks DOM order and screen-reader parity. -->
<form>
  <label>Name <input type="text" tabindex="3" /></label>
  <label>Email <input type="email" tabindex="1" /></label>
  <label>Phone <input type="tel" tabindex="2" /></label>
  <button type="submit" tabindex="4">Submit</button>
</form>

<!-- GOOD: rely on DOM source order. tabindex="0"
     only on the custom widget, tabindex="-1" only
     on the programmatic focus target. -->
<form>
  <label>Email <input type="email" /></label>
  <label>Name  <input type="text"  /></label>
  <label>Phone <input type="tel"   /></label>

  <!-- Custom widget: not focusable by default,
       so it needs tabindex="0". -->
  <div role="button" tabindex="0" onClick={submit}>
    Submit
  </div>
</form>

<!-- Skip-link target: focusable from JS but not
     in the Tab order. -->
<main id="main-content" tabindex="-1">…</main>

How to Check Tabindex Issues on Your Site

tabindex problems are usually invisible until a keyboard user tries to navigate. A combination of automated scanning and manual Tab-key testing surfaces them quickly.

  • Greadme deep scan — flags every element with positive tabindex, every interactive ARIA role missing keyboard focusability, and pairs each finding with an AI-generated fix or one-click GitHub PR.
  • Greadme crawler scan — runs the same checks across every indexable page, so you can spot which page templates carry the legacy positive-tabindex patterns.
  • Greadme AI visibility analyzer — tells you whether failing keyboard accessibility is dragging down rankings that AI search engines source from.
  • Manual keyboard test: press Tab from the address bar and walk through every interactive element. Focus order should match visual reading order; nothing should be skipped, and no focus indicator should disappear.
  • Open-source axe-core — the engine behind most accessibility scanners; it checks tabindex rules and ARIA focusability locally during builds.
  • Screen reader walkthrough: NVDA, JAWS, or VoiceOver. If the screen-reader order and Tab order disagree, you almost certainly have a positive tabindex somewhere.
  • Chrome DevTools Accessibility pane — inspect each element's computed accessibility tree, including its tabindex value and whether it is reachable via keyboard.

10 Tabindex Best Practices

1. Prefer Native Interactive Elements

<button>, <a href>, <input>, <select>, and <textarea> are focusable by default. Reach for them before reaching for tabindex. You get keyboard, screen-reader, and form-semantics behaviour for free.

2. Never Use Positive Tabindex

If you find yourself wanting tabindex="1", the answer is to reorder the DOM instead. Visual order and source order should match — that is exactly what WCAG 2.4.3 asks for.

3. Use tabindex="0" Only on Custom Widgets

When you build a <div role="button">, <div role="tab">, or any other custom interactive component, add tabindex="0" so keyboard users can reach it. Never add it to a native <button>.

4. Use tabindex="-1" for Programmatic Focus Targets

Skip-link targets, modal containers, route-change landing points, and post-validation error summaries all need to be programmatically focusable but not in the Tab sequence. tabindex="-1" is the right fit.

5. Don't Add Tabindex to Non-Interactive Content

Adding tabindex="0" to a paragraph or heading creates a focus stop with nothing to do — confusing for keyboard users who expect each Tab press to land on something they can act on.

6. Pair tabindex="0" With Keyboard Event Handlers

A custom button needs more than focusability — it needs to respond to Enter and Space. Add onKeyDown handlers that trigger the same action as the click handler.

7. Manage Focus on Route Changes in SPAs

In single-page apps, browsers don't reset focus when the URL changes. Move focus programmatically to a tabindex="-1" heading or main region after each route transition so screen readers announce the new page.

8. Trap Focus Inside Modal Dialogs

When a modal opens, focus should move into it (use tabindex="-1" on the dialog and .focus() it), and Tab should cycle within it until the modal closes. On close, return focus to the element that opened it.

9. Keep Focus Visible (WCAG 2.4.7)

tabindex only matters if the user can see where focus has landed. Don't override the browser's focus ring with outline: none unless you replace it with an equally visible custom indicator.

10. Audit Before Each Release

Tab order regressions usually arrive with someone refactoring a layout. Run an automated tabindex check in CI plus a manual Tab walkthrough of any page that changed structure.

Common Tabindex Mistakes and Fixes

Problem: tabindex="1" Used to Make a Field "Focus First"

What's happening: a developer wanted the email field to receive focus before the name field, so they added tabindex="1". Now keyboard users land on email first, then jump backwards to name — and any new field added later inherits a confusing position.

Fix: reorder the DOM so the email field appears before the name field in source. Remove every positive tabindex. If a specific field should receive focus on page load, call .focus() on it once after mount.

Problem: Custom <div role="button"> Without Tabindex

What's happening: the element looks like a button and clicks like a button, but Tab skips over it. Keyboard and screen-reader users can't activate it at all — a silent WCAG 2.1.1 failure.

Fix: add tabindex="0" and an onKeyDown handler that triggers the action on Enter and Space. Better still, replace it with a real <button>.

Problem: Skip-Link Target Has No tabindex="-1"

What's happening: the skip link points to <main id="main">, but in some browsers focus does not move to a non-interactive element on hash navigation. Users press the skip link and nothing seems to happen.

Fix: add tabindex="-1" to the <main> element. This makes it programmatically focusable so the browser can place focus there reliably.

Problem: tabindex="0" on Decorative Content

What's happening: a static <p> or hero image carries tabindex="0", so keyboard users get a focus stop on something they can't do anything with. Tab order doubles in length and feels broken.

Fix: remove the attribute. tabindex="0" belongs only on elements that are genuinely interactive.

Tabindex Values Compared

A direct side-by-side reference for which value to reach for in each situation.

ValueIn Tab order?Programmatically focusable?Use it for
(no attribute)Native interactive elements onlySameDefault — best choice for native HTML controls.
tabindex="0"Yes, in DOM orderYesCustom widgets like <div role="button">, custom tabs, custom listboxes.
tabindex="-1"NoYesSkip-link targets, modal containers, error summaries, SPA route-change focus targets.
tabindex="1"+Yes, before all other focusable elementsYesAlmost never. Violates WCAG 2.4.3 Focus Order in nearly all real-world cases.

FAQ

What does tabindex="0" do?

It makes an element that is not normally focusable (like a <div>) part of the keyboard Tab sequence, at its DOM position. Use it on custom interactive widgets. It is redundant — and considered noise — on elements that are focusable by default such as <button> or <a href>.

What does tabindex="-1" do?

It removes the element from the Tab sequence but lets JavaScript move focus to it via element.focus(). The standard use cases are skip-link targets, modal containers, error-summary panels, and route-change landing points in single-page apps.

Why is positive tabindex considered an anti-pattern?

Three reasons. It almost always conflicts with visual and source order, which violates WCAG 2.4.3 Focus Order. Once a user passes the last positive value, focus jumps back to the start of the natural order — confusing and disorienting. And screen readers usually walk the DOM regardless, so keyboard-only and screen-reader users end up on different paths through the same page.

Does tabindex affect screen readers?

Mostly no — screen readers navigate by DOM order, headings, landmarks, and the accessibility tree, not by tabindex. Positive values are typically invisible to them, which is exactly why they create a mismatch with keyboard-only users.

Should I add tabindex="0" to every interactive element?

No. Add it only when the element is not already focusable. Native form controls, links, and buttons are focusable by default; adding tabindex="0"to them is redundant and clutters the markup. Reserve it for custom widgets that the browser doesn't recognise as interactive.

How does tabindex affect AI search engines like ChatGPT and Perplexity?

Indirectly but meaningfully. Generative search systems most often surface pages that already rank well in traditional search, and Google factors keyboard-accessibility signals into its quality and Page Experience evaluations. A page where positive tabindex creates broken Tab order is more likely to fail those checks, lose ranking, and never be sourced by AI Overviews or chat-based answer engines.

How do I fix a focus order that doesn't match visual order?

Reorder the DOM so source order matches the visual layout, then remove every positive tabindex. Use CSS Grid's orderproperty only when truly necessary, and verify with a manual Tab walkthrough that focus follows the same path as a sighted user's reading flow.

Conclusion

tabindex is a small attribute with outsized impact. Use 0 sparingly to add custom widgets to the natural Tab order, use -1 for programmatic focus targets like skip-link destinations and modals, and never use a positive value. Combined with semantic HTML and visible focus styles, those rules satisfy WCAG 2.1.1, 2.4.3, and 2.4.7 — and keep your site usable for the roughly 1 in 4 people who depend on keyboard or assistive technology.

Run a Greadme deep scan to surface every positive tabindex, every interactive ARIA role missing focusability, and every focus-order regression on your site — each paired with an AI-generated fix or a one-click GitHub PR.