WCAG 3.2.1 · Level A · ADA Title II

Focus without surprises and the ADA

Landing on a field with the keyboard must not open windows, submit forms or move focus. Examples from permit and filing forms.

Landing on a field is not a command

Keyboard and switch users move through a page by tabbing. Screen reader users do the same, and mouse users give focus to a field simply by clicking it. In all those cases, receiving focus only means "this is where I am". WCAG 2.1 success criterion 3.2.1 says that when any user interface component receives focus, it must not initiate a change of context: no new window, no form submission, no jump of focus to another control, no navigation to a new page.

Activating a control, for example pressing Enter on a button, can legitimately change context. That is covered by other rules. This one is only about the moment of arrival. Content that appears without changing context (a tooltip, an expanded menu or an inline hint) is not a violation unless focus is also moved.

What counts as a change of context

  • Opening a new window or tab.
  • Submitting a form.
  • Moving keyboard focus to a different component than the one the user chose.
  • Replacing the main content so that it amounts to a different page, or changing the viewport in a way that disorients.

Where public sites trip up (ADA angle)

A common pattern is a convenience feature added to speed up forms: a search box that opens a full-screen overlay as soon as it receives focus, a ZIP field that opens a help window, or a month field that pushes focus to the day field the moment it is focused. For a keyboard user tabbing through a court e-filing or permit form, each of these hijacks the journey. The rule applies equally to the cross-field jump on a mobile app. Related: mobile apps and the Title II rule.

Web code: search, help windows, field jumps, menus

Search overlay on a transit planner

Incorrect
<input id="trip-search" onfocus="openFullScreenSearch()">
Correct
<input id="trip-search" aria-label="Search stops">
<button type="button" id="open-search">Open full-screen search</button>
<script>
  document.getElementById("open-search")
    .addEventListener("click", openFullScreenSearch);
</script>

Help opens in a new window on focus

Incorrect
<input id="permit-no" onfocus="window.open('/help/permit-number')">
Correct
<label for="permit-no">Permit number</label>
<input id="permit-no" aria-describedby="permit-help">
<p id="permit-help">Printed on the top right of your permit card.
  <a href="/help/permit-number" target="_blank" rel="noopener">More help (opens in new tab)</a>
</p>

A field that pushes focus to another field

Incorrect
month.addEventListener("focus", () => day.focus());
Correct
<!-- Let the user move between fields themselves -->
<label for="month">Month</label><input id="month" inputmode="numeric">
<label for="day">Day</label><input id="day" inputmode="numeric">
<label for="year">Year</label><input id="year" inputmode="numeric">

Mobile code: SwiftUI and Jetpack Compose

Incorrect
// SwiftUI
@FocusState private var focused: Field?
...
.onChange(of: focused) { new in
  if new == .address { showFullScreenSearch = true }
}
Correct
// SwiftUI
TextField("Address", text: $address)
Button("Open full-screen search") { showFullScreenSearch = true }
Incorrect
// Jetpack Compose
OutlinedTextField(
  value = query, onValueChange = { query = it },
  modifier = Modifier.onFocusChanged {
    if (it.isFocused) navController.navigate("search")
  }
)
Correct
// Jetpack Compose
OutlinedTextField(value = query, onValueChange = { query = it })
TextButton(onClick = { navController.navigate("search") }) {
  Text("Open full-screen search")
}

A keyboard-first test pass

  1. Using only the Tab key, move through every form and menu on a page. Watch for anything that opens, jumps or navigates without you pressing Enter or Space.
  2. Do the same with a screen reader, which can reveal handlers that fire only on programmatic focus.
  3. Click into text fields with a mouse and watch for overlays or new windows.
  4. Search the code for onfocus, addEventListener("focus", focusin and, in native code, focus-change callbacks that navigate or move focus.
  5. Tools: static checks flag inline focus handlers but cannot judge whether they change context. Plan a manual pass.

Pitfalls

  • Treating hover and focus as the same event. Opening a submenu on focus is fine only if it does not move focus or change the page.
  • Moving focus into a dialog automatically in response to focus elsewhere.
  • Moving focus into a "helper" field as soon as another field is focused. (Auto-advancing after a character is typed is an on-input behavior, covered by 3.2.2.)
  • Redirecting focus to another control the moment a field receives it, for example to start a wizard step.

Ship it when

  • Tabbing through each page never opens, submits, navigates or moves focus unexpectedly.
  • Any shortcut that jumps somewhere has an explicit button.
  • Help and extra information appear in place or via a link the user chooses to follow.

Sources

Standard version: WCAG 2.1 (W3C Recommendation, 5 June 2018), as named in the Title II web rule. This page is for informational purposes only and is not legal advice. For binding requirements, refer to the official ADA statute and regulations, and ask a lawyer how they apply to you.

Corpowid is recognized by Gartner

Corpowid has been recognized by Gartner, a leading global research and advisory firm, for our innovation and performance in digital accessibility. These badges reflect our commitment to creating inclusive, AI-powered web experiences.

Have questions about Corpowid?

Let’s connect.

We will get back to you as soon as possible.