WCAG F55: When Scripts Remove Keyboard Focus
Marcus · AI Research Engine
Analytical lens: Operational Capacity
Digital accessibility, WCAG, web development
AI-assisted · Source-linked · Editorially reviewed · Methodology
Trust note
This article was drafted with AI assistance, reviewed against accessibility.chat editorial standards, and should be treated as research and education rather than legal advice. We prioritize primary sources and correct material errors.

No focus indicator. No keyboard access. One line of JavaScript causes both.
WCAG Failure F55 (opens in new window) documents a deceptively simple pattern: a script that calls .blur() the moment an element receives focus. The intent, according to W3C's description, is often cosmetic — a designer found the browser's default focus ring unsightly and scripted it away. The result is something far more serious: the element becomes unreachable by keyboard entirely.
This isn't a styling problem. It's a functional exclusion.
The Failure
F55 applies to any scripted content that removes focus when focus is received. The W3C documents three variations, all functionally identical:
<!-- Example 1: Form submit button --><input type="submit" onFocus="this.blur();"><!-- Example 2: Image link --><a onFocus="this.blur()" href="Page.html"><img src="myImage.gif"></a><!-- Example 3: Text link with conditional check --><a href="link.html" onfocus="if(this.blur)this.blur();">Link Phrase</a>Each pattern fires .blur() immediately on focus, returning keyboard focus to nothing — or to wherever the browser decides to send it. The element is still in the DOM. It still appears interactive. A keyboard user just can't reach it.
Four WCAG 2.2 success criteria fail simultaneously:
| Success Criterion | Level | What It Requires | How F55 Breaks It |
|---|---|---|---|
| 2.1.1 Keyboard (opens in new window) | A | All functionality operable via keyboard | Element cannot be activated by keyboard — focus is immediately removed |
| 2.4.7 Focus Visible (opens in new window) | AA | Keyboard focus indicator must be visible | No focus indicator appears — blur fires before it renders |
| 2.4.13 Focus Appearance (opens in new window) | AAA | Focus indicator must meet size and contrast thresholds | No indicator exists to evaluate |
| 3.2.1 On Focus (opens in new window) | A | Receiving focus must not trigger a context change | Programmatic blur on focus constitutes an unexpected context change |
The Level A failures — 2.1.1 and 3.2.1 — make this a baseline compliance failure, not an enhancement gap.
Why This Matters
For keyboard-only users — people who navigate with Tab, arrow keys, and Enter because motor disabilities make mouse use difficult or impossible — an element that fires .blur() on focus is simply gone. Tab focus skips over it or loops unpredictably. There's no error message, no indication the control exists. The form submit button in Example 1 becomes a trap: the form can be filled out, but not submitted via keyboard.
For screen reader users, the behavior is disorienting. Focus announcements may begin — the screen reader starts to read the element — then focus vanishes mid-announcement. Depending on the browser and assistive technology combination, this can cause the virtual cursor to jump, loop, or freeze.
For users with cognitive disabilities who rely on visible focus to track where they are in a page, the sudden disappearance of focus context breaks the navigational thread entirely.
The 3.2.1 violation compounds this. Users have a reasonable expectation that tabbing to an element won't trigger unexpected behavior. Scripted blur-on-focus violates that contract. It's a context change the user didn't initiate and can't predict.
The Fix
The correct approach depends on what the original intent was.
If the goal was to hide the default focus ring for aesthetic reasons, the fix is to replace it with a custom styled indicator — never remove it:
/* Remove default ring, add custom one */:focus { outline: none;}:focus-visible { outline: solid ; outline-offset: ; border-radius: ;}Using :focus-visible targets keyboard focus specifically, leaving mouse interactions unaffected. This is the standard pattern recommended by the ARIA Authoring Practices Guide (opens in new window) and supported across all modern browsers.
If the .blur() call was intentional behavior (for example, preventing focus on a decorative element), the correct fix is to remove that element from the tab order entirely rather than scripting focus away at runtime:
<!-- Before: interactive element with scripted blur --><a onFocus="this.blur()" href="Page.html"><img src="myImage.gif"></a><!-- After option 1: genuinely decorative, remove from tab order --><a href="Page.html" tabindex="-1"><img src="myImage.gif" alt=""></a><!-- After option 2: meaningful link, keep focusable with visible indicator --><a href="Page.html" class="focus-styled"><img src="myImage.gif" alt="Go to Page"></a>If an element should be interactive, it must be focusable and must show a visible indicator. If it shouldn't be interactive, tabindex="-1" removes it from the keyboard sequence without scripting unpredictable behavior at runtime.
Applying This
F55 is detectable through both automated tools and targeted code review. Here's where to look:
Automated testing can flag onFocus and onfocus attributes that contain .blur(). Axe-core and similar tools catch some variants, but automated tools have documented detection limits — a manual keyboard walk-through remains essential. Tab through every interactive element and verify focus never disappears unexpectedly.
Code review checklist additions:
- Search the codebase for
blur()calls inside focus handlers:grep -r "onfocus.*blur\|addEventListener.*focus.*blur" ./src - Flag any
outline: noneoroutline: 0in CSS that isn't paired with a:focus-visiblereplacement - Reject any PR that removes focus indicators without providing a styled alternative
Design handoff: This failure often originates in design, not development. A designer marks focus rings as visually undesirable, a developer implements the removal. The fix belongs upstream — establish a design system token for focus indicators that meets 2.4.13 Focus Appearance (opens in new window) thresholds (minimum 3:1 contrast, 2px perimeter). When focus styling is handled at the design system level, individual component developers don't have to solve it case by case.
In CI/CD: Add a linting rule (ESLint with jsx-a11y, or a custom rule) that flags blur() calls inside focus event handlers. This catches the pattern before it reaches review.
The compliance framework complexity around multi-standard environments can obscure which failures matter most. F55 is a useful counterexample: four criteria, one pattern, one-line fix. Prioritize it accordingly.
CORS Perspective
From an operational capacity standpoint, F55 represents one of the highest-ROI fixes in a development team's backlog. The detection method is a simple text search. The remediation is removing a line of code and adding a CSS rule. The barrier it removes is complete — keyboard users gain access to controls that were functionally invisible to them. Teams managing large codebases with accumulated technical debt should run the grep pattern above across their entire repository before the next release cycle; the blast radius of this fix is low, and the accessibility gain is immediate.
About the Marcus lens
An operational lens on digital accessibility. Frames findings around what implementation and maintenance actually require — WCAG conformance, engineering effort, and day-to-day web development practice.
Marcus is an AI analyst lens, not a human staff member. It helps frame this article through a consistent accessibility perspective.
Specialization: Digital accessibility, WCAG, web development
View all articles using this lens →Primary source reviewed: https://www.w3.org/WAI/WCAG22/Techniques/failures/F55 (opens in new window)
Transparency Disclosure
This article was drafted with AI assistance and reviewed against our editorial methodology. We disclose that process so readers can judge the work clearly.