focus-not-removed-by-script

A script must not remove focus from an element as it receives it

automaticWCAG 2.1.1, 2.4.7 (AA)confidence: mediumseverity: seriousoperable

Fails elements in the tab order whose inline onfocus handler only calls blur() on them, and asks about other handlers that call blur(), or focus() on another element, which can remove focus as soon as the element receives it (WCAG failure F55).

Applies to. Elements that can take focus, that the page renders, and whose inline onfocus handler calls blur(), or focus() on another element. Without such an element, or in a document where none can take focus, nothing is applicable.

Expectation. WCAG failure F55: a script that removes focus from an element when it receives it leaves a keyboard user unable to reach or operate it, and unable to see where focus is.

  • FOCUS_HANDLER_BLURS_SELF: fail, on an element in the tab order, when the handler does only that (this.blur(), blur(), or blur() on event.target or event.currentTarget, by name or in brackets, possibly behind if (this.blur), with at most a return), as F55's examples do. Focus goes nowhere: it is dropped, not sent elsewhere. Outside the tab order (tabindex="-1"), where a keyboard user doesn't reach it, it is asked about.

Each other element is asked about (cantTell):

  • FOCUS_HANDLER_CALLS_BLUR when it calls blur() among other code, or on another element, where whether focus is lost depends on the script;
  • FOCUS_HANDLER_MOVES_FOCUS when it calls focus() on another element (document.body.focus()), which takes focus away as it arrives, as F55's test checks.

A handler that sends focus somewhere (a focus-trap sentinel, a redirect) is the moves case and is asked about, never failed: the rule reads the handler's text, not what the page does, and a person can confirm it by tabbing to the element.

What a finding reports.

  • reasonCode: FOCUS_HANDLER_BLURS_SELF, FOCUS_HANDLER_CALLS_BLUR or FOCUS_HANDLER_MOVES_FOCUS.
  • handler: the onfocus attribute's value, whitespace collapsed, up to 120 characters; a longer one is cut and ends in ….
  • tabbable: whether the element is in the tab order. One that is not can still receive focus from a click or a script.

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

fail
<a href="/offers" onfocus="this.blur()">Offers</a>

The link removes focus from itself as soon as it receives it, WCAG failure F55's own example: a keyboard user can't stay on it to follow it.

can't tell
<button type="button" onfocus="if (locked) this.blur(); track('focus')">Send</button>

The handler calls blur() among other code, so whether focus is lost depends on the script.

n/a
<span onfocus="this.blur()">Label</span>

The <span> cannot take focus, so its handler never runs.

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.

FOCUS_HANDLER_BLURS_SELF

  1. Click just before the element the report names, then press Tab until focus should reach it (if it is not in the tab order, click it instead).
  2. Watch the focus indicator and, in the developer tools console, check document.activeElement.
  3. Press Tab once more and see where focus goes.

Pass. Focus stays on the element, its focus indicator shows, and the next Tab moves on to the next control.

Fail. Focus disappears from the element as it arrives, so it cannot be reached or operated by keyboard, which fails WCAG 2.1.1 and 2.4.7 (F55).

FOCUS_HANDLER_CALLS_BLUR

  1. Read the onfocus handler the report quotes and note when it calls blur() and on which element.
  2. Click just before the element, then press Tab until focus should reach it; repeat in any state the handler tests for (for example, a field filled in or empty).
  3. Watch the focus indicator and check document.activeElement in the developer tools console.
  4. Try to operate the element with the keyboard (type, press Enter or Space).

Pass. In every state, focus stays on the element, its focus indicator shows, and it can be operated by keyboard.

Fail. In some state focus is removed as the element receives it, so it cannot be operated by keyboard or focus is lost from view, which fails WCAG 2.1.1 and 2.4.7 (F55).

FOCUS_HANDLER_MOVES_FOCUS

  1. Read the onfocus handler the report quotes and note which element it sends focus to.
  2. Click just before the element, then press Tab until focus should reach it, and see where focus lands (check document.activeElement in the console).
  3. If the element is an invisible, unnamed sentinel at the edge of a dialog that wraps focus back inside, note that this is a focus trap for a modal and expected.
  4. Otherwise, try to operate the element with the keyboard and press Shift+Tab to see whether you can go back.

Pass. Focus goes to a sensible place (a dialog's focus wrap) or stays on the element, and every control can still be reached and operated by keyboard.

Fail. A visible control sends focus elsewhere as it arrives, so it cannot be reached or operated by keyboard, which fails WCAG 2.1.1 and 2.4.7 (F55).

View source