click-handler-keyboard-operable
Click handlers on elements that are not native controls must work by keyboard
Checks that an element that is not a native control and has a click handler (an inline onclick, or a click listener the listener hook saw) can take keyboard focus and that a key handler on it, an ancestor or a descendant receives its keys, so a keyboard user can run what a click runs.
Applies to. Elements the page renders with a non-empty inline onclick attribute, or, where the page runs the listener hook (listenerHookScript), with a click listener added from script (addEventListener('click', …) or the onclick property) on the element itself, except:
<html>and<body>, where a click handler serves the whole page;- a handler made only of statements that do nothing (
return false,void(0),void 0,event.preventDefault()): it offers no function; - an element with
aria-disabled="true", on itself or an ancestor: a disabled control offers no function to operate; - native controls, whose own keyboard behaviour reaches the user: a link or area with
href,button,inputother than hidden,select,textarea,option,summary,label(it activates its control, which takes focus itself),iframe,embed,audioorvideowithcontrols, and an editing host (contenteditable); - an element containing, in the flat tree (its shadow root and slotted content included), a control whose keyboard activation fires
click(a link or area withhref,button,summary, or an input of type button, submit, reset, image, checkbox or radio) that is in the tab order: the control's click bubbles to the handler, so this is event delegation and the keyboard already runs it; - an element that cannot take focus, has no descendant that can, has no widget role and no
cursor: pointer: nothing tells the user it is clickable, and such a handler often only tracks clicks or stops their propagation.
Expectation. A keyboard user can run what the click runs. Chromium fires click on Enter or Space for native controls only: a <span role="button" tabindex="0" onclick> gets focus but does nothing on either key.
- The element, or one of its flat-tree descendants, is in the tab order, and an inline key handler (
onkeydown,onkeyup,onkeypress) is on it, an ancestor or a descendant, so key events from the focused element can reach one: pass. - The element or a descendant is in the tab order, but no inline key handler is there: cantTell (
CLICK_HANDLER_NO_KEY_HANDLER), check that Enter and Space do what a click does. - The element or a descendant can take focus, but only with
tabindex="-1", and no ancestor has a key handler: cantTell (CLICK_HANDLER_NOT_IN_TAB_ORDER). Tab never reaches it; a script may move focus there, as a roving tabindex does. - With the listener hook, a key listener added from script on the element or a descendant counts as an inline key handler does. One only on an ancestor, a shadow root the element is in, the document or the window may handle the element's keys or only others': cantTell (
CLICK_HANDLER_KEY_LISTENER_ABOVE). - The element is in the tab order, its role is button, link, checkbox, switch, tab, menuitem, menuitemcheckbox or menuitemradio, and a hook installed before the page's scripts saw no key listener on it, a descendant, an ancestor, a shadow root it is in, the document or the window, nor is an inline key handler there: fail (
CLICK_HANDLER_NO_KEY_LISTENER). No key event reaches a handler, so Enter and Space do nothing. Unless a focus or focusin listener is on it, an ancestor, a shadow root it is in, the document or the window: it may add the key listener once the element has focus, or, for a tab, show its panel on focus, so cantTell (CLICK_HANDLER_FOCUS_LISTENER). - Neither it nor a descendant can take focus, and its role is button, link, checkbox or switch: fail (
CLICK_HANDLER_CONTROL_NOT_FOCUSABLE). The element says it is a control, and Tab never reaches it, as in WCAG failure F42 for scripted links. Unless an ancestor carriesaria-activedescendantor an inline key handler, or is a focusable composite widget (grid, treegrid, listbox, menu, menubar, tree, tablist, toolbar, radiogroup, combobox), which may operate it without moving focus to it: then cantTell. - Neither it nor a descendant can take focus, with another widget role or
cursor: pointer: cantTell (CLICK_HANDLER_NOT_FOCUSABLE). An option of a combobox's list or a cell of a grid is often operated from the element that keeps focus, and the action may be offered by another control of the page.
What a finding reports.
role: the element's ARIA role, or''for none.focusable: whether the element itself can take focus.
These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.
Examples
<span role="button" tabindex="0" onclick="save()" onkeydown="if (event.key === 'Enter' || event.key === ' ') save()">Save</span>
The span takes focus and its key handler runs the same action as the click.
<div role="button" onclick="openPanel()">Open the panel</div>
The element says it is a button and runs a click handler, but keyboard focus can never reach it.
<span role="button" tabindex="0" onclick="showPreferences()">Manage my cookies</span>
The span takes focus, but Enter and Space fire no click on it and it has no inline key handler; a listener added from script would not show in the markup.
How to check
When this rule can’t decide, it reports cantTell and leaves the question to a person. Each question it can ask is listed here under its reason code, with the steps to answer it. A finding carries the same steps as howToCheck, in the scan’s language. See Output schema.
CLICK_HANDLER_FOCUS_LISTENER
- Click the element the report names and note what happens.
- Reload, then press Tab until the element has focus.
- Press Enter, then Space, and compare with what the click did.
- If the keyboard can't do it here, check whether what the click does can be done another way with the keyboard alone, for example with a button or menu item elsewhere on the page. It only counts if it does everything the click does.
Pass. Enter (and Space for button-like controls) does what a click does, or, for a tab, moving focus to it already shows its panel, or what the click does can be done another way with the keyboard alone.
Fail. Pressing Enter or Space does nothing even after focus arrives, and what the click does cannot be done another way with the keyboard, which fails WCAG 2.1.1 (F54).
CLICK_HANDLER_KEY_LISTENER_ABOVE
- Click the element the report names and note what happens.
- Press Tab until the element has focus.
- Press Enter, then Space (and the arrow keys if it sits in a group), and compare with the click.
- If the keyboard can't do it here, check whether what the click does can be done another way with the keyboard alone, for example with a button or menu item elsewhere on the page. It only counts if it does everything the click does.
Pass. Enter (and Space for button-like controls) does what a click does, or what the click does can be done another way with the keyboard alone.
Fail. Pressing Enter or Space does nothing on the element, so the listener above does not handle it, and what the click does cannot be done another way with the keyboard, which fails WCAG 2.1.1.
CLICK_HANDLER_NOT_FOCUSABLE
- Click the element the report names and note what its click does.
- Press Tab through the page and check that the element never takes focus.
- If it is an item in a list, grid or combobox, focus that widget and use the arrow keys to see whether the item becomes active and Enter performs the action.
- Otherwise look for another keyboard-operable control on the page that does the same thing.
Pass. The same action can be done by keyboard, through the managing widget or another control.
Fail. The action can only be done with a mouse, which fails WCAG 2.1.1 (F54, F42).
CLICK_HANDLER_NOT_IN_TAB_ORDER
- Click the element the report names and note what happens.
- Press Tab through the page and check whether focus ever lands on it.
- If it is part of a group (tabs, menu, toolbar, list), Tab into the group and use the arrow keys to see whether they move focus to it.
- Once it has focus, press Enter or Space and compare with the click.
- If the keyboard can't do it here, check whether what the click does can be done another way with the keyboard alone, for example with a button or menu item elsewhere on the page. It only counts if it does everything the click does.
Pass. The element can be reached by keyboard (Tab or arrow keys within its group) and Enter or Space does what a click does, or what the click does can be done another way with the keyboard alone.
Fail. No key moves focus to the element and what the click does cannot be done another way with the keyboard, so its action is mouse-only, which fails WCAG 2.1.1.
CLICK_HANDLER_NO_KEY_HANDLER
- Click the element the report names and note what happens.
- Reload, then press Tab until the element has focus.
- Press Enter, then Space, and compare with what the click did.
- If the keyboard can't do it here, check whether what the click does can be done another way with the keyboard alone, for example with a button or menu item elsewhere on the page. It only counts if it does everything the click does.
Pass. Enter (and Space for button-like controls) does what a click does, or what the click does can be done another way with the keyboard alone.
Fail. Pressing Enter or Space does nothing, or less than a click, and what the click does cannot be done another way with the keyboard, which fails WCAG 2.1.1 (F54).