# Receiving focus does not cause unexpected navigation

- **Pattern:** `ab-000118` (`accessibility-wcag.understandable.focus-change`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000118
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000118)

## Why it matters

When tabbing to an element automatically triggers navigation, form submission, or a dialog, keyboard users lose control over when actions happen. WCAG 2.2 SC 3.2.1 (On Focus) is a Level A requirement: receiving focus must never automatically cause a context change. Users with motor disabilities who accidentally land on a focusable element before their intended target will trigger unintended actions — potentially submitting forms or navigating away from work in progress.

## Severity rationale

Low because focus-triggered navigation is only a violation when `onFocus` handlers explicitly cause context changes — the default HTML behavior is safe, so scope is limited to explicit misuse of the event.

## Remediation

Remove `onFocus` handlers that trigger navigation or submission. Separate the display of options from their activation — selection should require an explicit action like clicking a button.

```tsx
// Bad — navigates on focus, no user confirmation
<select onFocus={(e) => router.push(e.target.value)}>
  <option value="/">Home</option>
  <option value="/settings">Settings</option>
</select>

// Good — selection updates state; navigation requires an explicit action
<select value={dest} onChange={(e) => setDest(e.target.value)}>
  <option value="/">Home</option>
  <option value="/settings">Settings</option>
</select>
<button onClick={() => router.push(dest)}>Go</button>
```

Search the codebase for `onFocus` event handlers. Any that call `router.push`, `window.location`, or `form.submit` are WCAG 2.2 SC 3.2.1 violations.

## Detection

- **ID:** `focus-change`
- **Severity:** `low`
- **What to look for:** Enumerate every relevant item. Keyboard-navigate through the page. Check for any elements that submit forms, navigate to a different page, or open dialogs purely from receiving focus (without an explicit Enter or Space key). Look specifically for `onFocus` event handlers that trigger navigation or form submission. The default behavior of HTML elements (receiving focus does nothing by default) is a pass.
- **Pass criteria:** At least 1 of the following conditions is met. Receiving focus does not trigger navigation, form submission, or unexpected dialogs. Interactions require explicit user action (Enter, Space, or click). Applications with no `onFocus` event handlers that trigger side effects pass by default.
- **Fail criteria:** An `onFocus` handler explicitly navigates, submits a form, or opens a dialog when an element receives keyboard focus without user intent.
- **Skip (N/A) when:** Never — focus change behavior applies to all interactive elements.
- **Detail on fail:** Example: `"Tabbing to a dropdown menu automatically opens it without user pressing Enter. Link in footer navigates on focus without click"`
- **Remediation:** Separate focus from interaction:

  ```tsx
  // Bad
  <select onChange={(e) => navigate(e.target.value)}>
    <option value="/">Home</option>
    <option value="/about">About</option>
  </select>

  // Good
  <select value={selectedPath}>
    <option value="/">Home</option>
    <option value="/about">About</option>
  </select>
  <button onClick={() => navigate(selectedPath)}>Go</button>
  ```

## External references

- wcag 3.2.1
- section-508 501.1

Taxons: accessibility

HTML version: https://auditbuffet.com/patterns/ab-000118
