Go Back

Tab Order

Definition

Tab order refers to the sequential path that focus follows when users navigate through interactive elements on a web page using the Tab key. It determines which elements receive keyboard focus and in what order, creating a logical navigation flow for users who rely on keyboards rather than mice or touch devices. A well-implemented tab order is essential for accessibility, enabling keyboard-only users, screen reader users, and those with motor disabilities to navigate interfaces efficiently.

The default tab order of a web page follows the DOM (Document Object Model) structure, moving from top to bottom and left to right in most languages. Elements that naturally receive focus include links, buttons, form controls, and any elements with interactive event handlers. When developers need to customize this sequence, they can use the tabindex attribute, though this should be done thoughtfully to maintain an intuitive navigation experience.

Importance in Accessibility

Proper tab order is critical for several reasons:

  1. Keyboard accessibility: Many users with motor disabilities rely exclusively on keyboards
  2. Screen reader navigation: Screen reader users often navigate via the tab key to discover interactive content
  3. Cognitive clarity: A logical focus sequence reduces cognitive load by creating predictable navigation
  4. Situational accessibility: Benefits users with temporary limitations, like a broken trackpad or in environments where mouse use is difficult

WCAG (Web Content Accessibility Guidelines) Success Criterion 2.4.3 specifically requires that the navigation order of focusable elements be logical and intuitive, reflecting the meaning and relationships in the content.

Implementing Proper Tab Order

HTML Structure

The most effective way to create a logical tab order is through proper HTML structure:

  1. Semantic markup: Organize content with semantic HTML elements that follow the natural reading order
  2. Logical document flow: Arrange elements in the DOM to match their visual presentation
  3. Form structure: Group related form fields using <fieldset> and <legend> elements
<form>
  <fieldset>
    <legend>Personal Information</legend>
    
    <label for="name">Full Name</label>
    <input id="name" type="text">
    
    <label for="email">Email Address</label>
    <input id="email" type="email">
  </fieldset>
  
  <fieldset>
    <legend>Shipping Address</legend>
    <!-- Address fields -->
  </fieldset>
  
  <button type="submit">Continue</button>
</form>

Using the tabindex Attribute

The tabindex attribute can control an element's position in the tab order:

  • tabindex="0": Includes an element in the natural tab order
  • tabindex="-1": Removes an element from the tab order but allows focus via JavaScript
  • tabindex="1+" (positive values): Places elements earlier in the tab order, but generally should be avoided
<!-- Included in natural tab order -->
<div tabindex="0" role="button">Custom Button</div>

<!-- Focusable by script but not in tab order -->
<div tabindex="-1" class="tooltip">Helpful information</div>

<!-- AVOID: Creates unintuitive tab order -->
<button tabindex="1">Submit</button>
<button tabindex="3">Cancel</button>
<button tabindex="2">Reset</button>

Note: Positive tabindex values should be used sparingly, as they can create unexpected and difficult-to-maintain tab sequences. They override the natural document order and can lead to confusing navigation patterns.

Skip links allow keyboard users to bypass repetitive navigation menus:

<a href="#main-content" class="skip-link">Skip to main content</a>

<!-- Rest of the header/navigation -->

<main id="main-content">
  <!-- Main content starts here -->
</main>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  padding: 8px;
  background: white;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}

Common Tab Order Issues and Solutions

Issue: Visual Order Differs from DOM Order

Problem: Elements appear in one order visually but are arranged differently in the DOM, creating a counterintuitive tab sequence.

Solutions:

  • Restructure HTML to match the visual layout
  • Rethink CSS positioning to maintain logical document flow
  • In complex layouts like grids, ensure the DOM order follows a logical reading pattern
<!-- PROBLEMATIC: Visual order doesn't match DOM order -->
<div style="display: flex; flex-direction: column;">
  <div style="order: 3;"><button>Submit</button></div>
  <div style="order: 1;"><input type="text"></div>
  <div style="order: 2;"><input type="email"></div>
</div>

<!-- BETTER: DOM order matches visual order -->
<div style="display: flex; flex-direction: column;">
  <div><input type="text"></div>
  <div><input type="email"></div>
  <div><button>Submit</button></div>
</div>

Issue: Non-Interactive Elements in Tab Order

Problem: Adding tabindex="0" to non-interactive elements like paragraphs or headings creates unnecessary tab stops.

Solution: Only make elements focusable if they're truly interactive.

<!-- PROBLEMATIC: Non-interactive element in tab order -->
<p tabindex="0">This is regular text.</p>

<!-- BETTER: Only interactive elements receive focus -->
<button>Interactive Button</button>
<a href="#">Link to Content</a>

Issue: Hidden or Offscreen Elements Receiving Focus

Problem: Elements that are visually hidden but still in the DOM receive focus, creating "invisible" tab stops.

Solutions:

  • Remove hidden elements from the tab order with tabindex="-1"
  • Use aria-hidden="true" for purely decorative content
  • For content hidden with CSS, ensure proper techniques that remove from both visual display and tab order
<!-- Hidden element removed from tab order -->
<div hidden tabindex="-1">Hidden content</div>

<!-- Decorative icon removed from accessibility tree -->
<span class="icon" aria-hidden="true"></span>

Issue: Modal Focus Trapping

Problem: Focus escapes modal dialogs, allowing users to interact with background content.

Solution: Implement focus trapping to keep focus within modal dialogs.

// Basic modal focus trap implementation
function trapFocus(modal) {
  // Get all focusable elements
  const focusableElements = modal.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  
  const firstElement = focusableElements[0];
  const lastElement = focusableElements[focusableElements.length - 1];
  
  // Handle Tab key press
  modal.addEventListener('keydown', function(e) {
    if (e.key === 'Tab') {
      // Shift + Tab on first element should wrap to last
      if (e.shiftKey && document.activeElement === firstElement) {
        e.preventDefault();
        lastElement.focus();
      } 
      // Tab on last element should wrap to first
      else if (!e.shiftKey && document.activeElement === lastElement) {
        e.preventDefault();
        firstElement.focus();
      }
    }
  });
  
  // Initially focus first element
  firstElement.focus();
}

Testing Tab Order

Thorough testing is essential to ensure proper tab order:

Manual Testing Methods

  1. Keyboard navigation test:

    • Disconnect your mouse/trackpad
    • Navigate the entire interface using only Tab, Shift+Tab, Enter, and Arrow keys
    • Verify the focus sequence follows a logical order
  2. Visual focus indicator test:

    • Ensure focus indicators are clearly visible on all interactive elements
    • Check that the focus moves predictably in a logical sequence
  3. Screen reader testing:

    • Test with screen readers like NVDA, JAWS, or VoiceOver
    • Confirm focus announcements match the visual focus position

Automated Testing Approaches

  1. Accessibility testing tools:

    • axe DevTools
    • Lighthouse
    • WAVE
  2. DOM order visualization:

    • Browser developer tools to examine the DOM structure
    • Extensions that visualize tab order sequence

Tab Order in Complex Interfaces

Modern web applications often include complex components that require special consideration for tab order:

Single-Page Applications

When content changes dynamically without page refreshes, focus management becomes critical:

  1. Set focus after navigation: Move focus to main heading or content area after route changes
  2. Maintain focus position: When possible, restore focus to the last active element after content updates
  3. Announce dynamic changes: Use ARIA live regions for significant content updates
// After SPA navigation
function handleRouteChange() {
  // Find the main heading in new content
  const mainHeading = document.querySelector('h1');
  
  // Set focus to main heading
  if (mainHeading) {
    mainHeading.tabIndex = -1;
    mainHeading.focus();
  }
}

Custom Widgets

Interactive components like tabs, accordions, and carousels require custom keyboard interaction patterns:

  1. Composite widgets: Implement both tab order between widgets and arrow key navigation within widgets
  2. ARIA patterns: Follow established design patterns from WAI-ARIA Authoring Practices
  3. Focus containment: Contain focus within appropriate boundaries for complex components
<!-- Tab interface with keyboard navigation -->
<div role="tablist">
  <button id="tab1" role="tab" aria-selected="true" aria-controls="panel1">Tab 1</button>
  <button id="tab2" role="tab" aria-selected="false" aria-controls="panel2">Tab 2</button>
</div>

<div id="panel1" role="tabpanel" aria-labelledby="tab1">
  <p>Content for Tab 1</p>
  <button>Action in Tab 1</button>
</div>

<div id="panel2" role="tabpanel" aria-labelledby="tab2" hidden>
  <p>Content for Tab 2</p>
  <button>Action in Tab 2</button>
</div>
// Implement arrow key navigation between tabs
document.querySelectorAll('[role="tab"]').forEach(tab => {
  tab.addEventListener('keydown', (e) => {
    const tabs = Array.from(document.querySelectorAll('[role="tab"]'));
    const index = tabs.indexOf(e.target);
    
    // Handle arrow keys
    if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
      const nextTab = tabs[(index + 1) % tabs.length];
      nextTab.focus();
      nextTab.click();
    } 
    else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
      const prevTab = tabs[(index - 1 + tabs.length) % tabs.length];
      prevTab.focus();
      prevTab.click();
    }
  });
});

Best Practices

For Developers

  1. Use semantic HTML: The most reliable way to ensure a logical tab order
  2. Minimize tabindex use: Rely on proper document structure over manual tab index management
  3. Test with keyboard only: Regularly navigate your site without a mouse
  4. Visible focus styles: Ensure focus indicators are clearly visible across all states and themes
  5. Consistency across viewports: Maintain a logical tab order in both mobile and desktop layouts

For Designers

  1. Consider tab sequence during design: Plan the user's journey through the interface via keyboard
  2. Indicate interactive elements clearly: Design patterns that visually communicate interactivity
  3. Provide clear focus states: Design visible focus indicators for all interactive elements
  4. Group related actions: Design interfaces where related actions are grouped together visually and in the tab sequence
  • Keyboard Navigation: The broader practice of making interfaces fully operable via keyboard
  • Focus Management: Techniques for directing keyboard focus to meaningful locations
  • ARIA Live Regions: Elements that announce dynamic content changes to screen reader users
  • Skip Links: Links that allow keyboard users to bypass repetitive navigation
  • Focus Trap: Technique to contain keyboard focus within modal dialogs or other temporary interfaces

Conclusion

Tab order is a fundamental aspect of web accessibility that impacts a wide range of users. While visual users can click directly on any element they wish to interact with, keyboard-only users must navigate through interactive elements sequentially. A logical, intuitive tab order is essential for creating inclusive digital experiences that can be used by everyone.

By prioritizing proper HTML structure, testing thoroughly with keyboards, and carefully implementing focus management in complex interfaces, developers can create experiences that work seamlessly for all users, regardless of how they navigate the web. A well-implemented tab order isn't just about accessibility compliance—it's about creating interfaces that are more usable and intuitive for everyone.