WCAG 2.1.1 · Level A · ADA Title II

Keyboard access and the ADA

Every function on a public-facing site has to work from a keyboard, not only with a mouse or touch. Here is how that plays out in permit, booking and transit tools.

What "keyboard operable" means in practice

Success Criterion 2.1.1 says all functionality must be operable through a keyboard interface, and that operation must not depend on specific timings for individual keystrokes. A "keyboard interface" is wider than a physical keyboard: switch devices, speech input, on-screen keyboards and screen readers all send key events to the page.

There is one narrow exception: functions whose input depends on the path of a movement and not just its endpoints, such as freehand drawing. Dragging a list item from one position to another is not covered by it, because it has a start and an end, so it needs a keyboard route as well.

The criterion does not require every control to be its own tab stop. A search field that submits when Enter is pressed is operable even though the submit button is never focused. What counts is that nothing can be done only with a pointer.

Where city, county and school sites usually fail

Government sites tend to be assembled from templates, vendor widgets and years of custom scripts, so the same few patterns come up again and again:

  • Appointment time slots built from <div> elements with a click handler.
  • Menus that open on mouse hover and have no keyboard equivalent.
  • Parcel, transit or park maps that can only be panned by dragging.
  • Image buttons such as "Pay now" that are really a clickable image.
  • Calendars and date pickers that respond to clicks only.

These are the barriers a person who cannot use a mouse meets first, and they tend to sit on the pages people must use: payments, bookings and applications. Under the Title II rule, a service a public entity offers online has to be usable without a pointer once the compliance date for that entity arrives.

Replace clickable divs with real controls

A native <button> is focusable, activates with Enter and Space, and announces its role. Rebuilding that with a <div> takes tabindex, a role and key handlers, and it is easy to miss one of them.

Example: time slots on a county clinic booking page.

Incorrect
<div class="slot" onclick="pickSlot('2026-03-04T09:30')">
  9:30 AM
</div>
Correct
<button type="button" class="slot"
        onclick="pickSlot('2026-03-04T09:30')">
  9:30 AM
</button>

Menus that open on hover need a button that does the same job from the keyboard:

Incorrect
<li class="has-menu" onmouseenter="openMenu(this)">
  Services
  <ul class="menu">…</ul>
</li>
Correct
<li>
  <button type="button" aria-expanded="false"
          aria-controls="svc-menu" onclick="toggleMenu(this)">
    Services
  </button>
  <ul id="svc-menu" hidden>…</ul>
</li>

Maps and other drag-only interfaces

Panning and zooming a transit trip planner map is not path-dependent in the sense of the exception: the user only needs to move the viewport somewhere. Provide arrow keys and zoom keys while the map has focus, or visible pan and zoom buttons.

Incorrect
<div id="map"></div>
<script>
  map.addEventListener("mousedown", startDrag);
  map.addEventListener("mousemove", dragMap);
</script>
Correct
<div id="map" tabindex="0" role="region"
     aria-label="Route map. Arrow keys pan, plus and minus zoom."></div>
<script>
  map.addEventListener("keydown", e => {
    const step = 40;
    if (e.key === "ArrowLeft")  panBy(-step, 0);
    else if (e.key === "ArrowRight") panBy(step, 0);
    else if (e.key === "ArrowUp")    panBy(0, -step);
    else if (e.key === "ArrowDown")  panBy(0, step);
    else if (e.key === "+") zoomBy(1);
    else if (e.key === "-") zoomBy(-1);
    else return;
    e.preventDefault();
  });
</script>

Because those single-character keys only work while the map has focus, they stay clear of the character-key shortcut rules in 2.1.4.

Mobile apps: hardware keyboards and switch control

Mobile apps are in scope of the Title II rule, and people do use Bluetooth keyboards, Full Keyboard Access on iOS, and switch devices on Android. A view that only listens for taps through a gesture recognizer is invisible to them.

SwiftUI, a park pass row:

Incorrect
HStack {
    Image(systemName: "ticket")
    Text("Reserve day pass")
}
.onTapGesture { reserve() }
Correct
Button(action: reserve) {
    Label("Reserve day pass", systemImage: "ticket")
}

Jetpack Compose, the same row:

Incorrect
Box(
    Modifier.pointerInput(Unit) {
        detectTapGestures(onTap = { reserve() })
    }
) { Text("Reserve day pass") }
Correct
Button(onClick = { reserve() }) {
    Text("Reserve day pass")
}

How to test without a mouse

  1. Unplug the mouse or stop using the trackpad. Start at the top of the page and press Tab through the whole task, for example booking an appointment from start to confirmation.
  2. Use Enter on links, Space or Enter on buttons, arrow keys inside menus, tabs and radio groups, and Esc to close overlays.
  3. Write down every action you could do with a mouse but not with the keyboard. Also note anything that needs a rapid double key press or a long key hold.
  4. On mobile, connect a hardware keyboard, turn on Full Keyboard Access (iOS) or use a Bluetooth keyboard with TalkBack (Android), and repeat.

Automated checkers can flag missing roles or focusable elements without names, but they cannot know that a plain <div> has a click handler, so the manual pass is the real test.

Mistakes that keep coming back

  • Putting tabindex="0" on a <div> and stopping there, without Enter and Space handling.
  • Using <a> without href for actions, which removes it from the tab order.
  • Hiding a control with display: none when it is still needed, or removing focus with a script.
  • Assuming that touch support covers screen reader and switch users.
  • Requiring a keystroke to be repeated quickly or held down.
  • Calling a function "drawing" so it can claim the path exception when only the start and end points matter.

Ship it when

  • A person can finish each key task using only the keyboard.
  • Every clickable element is a native control, or has a role, a tab stop and key handling.
  • Hover-only content can also be opened by focus or by a button.
  • Maps, sliders and drag-and-drop lists have a non-pointer way to do the same thing.
  • Nothing relies on timed keystrokes.

See also the guidance on common barriers that DOJ lists, which includes mouse-only navigation.

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.