A <div onClick={handler}> that renders as a clickable UI element with no keyboard equivalent shuts out every user who does not use a pointer device — keyboard-only users, switch access users, and users on devices with no pointing hardware. WCAG 2.2 SC 2.1.1 (Keyboard) requires all functionality to be operable via keyboard without requiring specific timings. Section 508 2018 Refresh 407.6 mandates keyboard operation for all standard functions. This is not a fringe scenario: approximately 26% of US adults with disabilities have a mobility disability affecting computer use. The most common failure patterns are custom dropdown menus that require hover/click, carousels that accept only swipe gestures, and custom select components built on <div> elements without role="option" and Arrow key handling.
Critical because mouse-only interactive elements completely block keyboard users from performing those actions, constituting an absolute access barrier.
Replace <div onClick> patterns with <button> elements wherever the element triggers an action. Use native form elements for inputs and selects. When a custom widget is unavoidable, implement the full ARIA authoring practices keyboard contract.
// Bad: Mouse-only
<div onClick={openMenu} className="menu-trigger">Menu</div>
// Good: Semantic button (keyboard support is built in)
<button onClick={openMenu}>Menu</button>
// Custom widget: implement keyboard contract per ARIA APG
<div
role="combobox"
tabIndex={0}
aria-expanded={isOpen}
aria-haspopup="listbox"
aria-labelledby="country-label"
onClick={toggle}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
toggle();
}
if (e.key === 'ArrowDown') {
e.preventDefault();
focusNextOption();
}
if (e.key === 'Escape') close();
}}
>
{selectedValue}
</div>
Reference the ARIA Authoring Practices Guide (APG) at aria.w3.org/apg/patterns/ for the correct keyboard contract for each widget type.
ID: accessibility-basics.keyboard-focus.keyboard-accessible
Severity: critical
What to look for: Enumerate every relevant item. Test keyboard navigation through the entire application. Check that all interactive elements (buttons, links, form inputs, custom controls) can be accessed and activated using Tab, Enter, Space, and Arrow keys as appropriate. Look for mouse-only interactions or components that do not respond to keyboard events.
Pass criteria: At least 1 of the following conditions is met. All interactive elements are operable via keyboard. Buttons activate with Enter or Space. Links navigate with Enter. Form inputs accept keyboard input. Custom controls respond to appropriate keyboard shortcuts (Tab, Arrow keys, etc.).
Fail criteria: Any interactive element cannot be accessed via keyboard, or a common interaction (e.g., clicking a custom button component) has no keyboard equivalent.
Skip (N/A) when: Never — keyboard accessibility applies to all interactive pages.
Detail on fail: Identify keyboard-inaccessible interactions. Example: "Custom select dropdown components do not respond to Arrow keys. Carousel only responds to mouse drag; no keyboard controls. Checkbox state changes require mouse click."
Remediation: Ensure all interactive elements respond to keyboard events:
{/* Bad: Mouse-only interaction */}
<div onClick={() => toggleMenu()}>Menu</div>
{/* Good: Keyboard-accessible button */}
<button onClick={() => toggleMenu()}>Menu</button>
{/* Custom control with keyboard support */}
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleClick();
}
}}
>
Custom Button
</div>