Focus indicator removed via CSS
focus/outline-removed
- WCAG success criterion
- 2.4.7 (level AA)
- Outcome class
- Automatic. An automated check that can report a confirmed violation.
- Area
- Accessibility, Navigation & Operation
- Default severity
- high
- axe-core rule
focus-visible-outline-none
Why we flag this
Keyboard users cannot see which element currently has focus.
outline: none/0 in :focus rules without an alternative visible focus indicator.
What the rule checks
Scope. Pages whose stylesheets contain a :focus rule that removes the outline (outline: none / 0, outline-style: none, outline-width: 0).
Expectation. violation once per page (page-level) when a stylesheet removes the focus outline under :focus and no rule replaces it: no :focus-visible rule anywhere and no :focus rule that sets another indicator (box-shadow, border, background, text decoration, or the outline itself). Rules inside a media query that applies on the phone viewport count, as do stylesheets a script injects after load. A replacement in the same rule, or a :focus-visible rule for keyboard focus, passes. Pages without such a rule are not applicable.
Source. WCAG 2.2 SC 2.4.7 Focus Visible; failure F78 (styling that removes or renders the focus indicator non-visible)
Detection: shared; needs stylesheets.
Failing example
The check reports a violation here. Corpus case interaction_outline_removed. The page may contain further findings for other rules.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Focus outline removed</title>
<style>
body { font-family: sans-serif; margin: 0; padding: 16px; color: #111; background: #fff; }
a, button { display: inline-block; min-width: 44px; min-height: 44px; padding: 12px; box-sizing: border-box; margin: 4px; }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: 16px; }
/* violation: removes the indicator and nothing replaces it */
a:focus { outline: none; }
button:focus { outline: 0; }
</style>
</head>
<body>
<a class="skip" href="#main">Skip to main content</a>
<header><p>Example Bank</p></header>
<nav aria-label="Main">
<a href="/" aria-current="page">Home</a>
<a href="/accounts">Accounts</a>
</nav>
<main id="main">
<h1>Focus outline removed</h1>
<p>Review your recent payments or <a href="/statements">download a statement</a>.</p>
<button type="button">Show more payments</button>
</main>
<footer><p>Example Bank footer</p></footer>
</body>
</html>Passing example
The check passes here and reports nothing. Corpus case interaction_outline_replaced. The page may contain further findings for other rules.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Focus outline replaced</title>
<style>
body { font-family: sans-serif; margin: 0; padding: 16px; color: #111; background: #fff; }
a, button { display: inline-block; min-width: 44px; min-height: 44px; padding: 12px; box-sizing: border-box; margin: 4px; }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: 16px; }
/* pass: the outline gives way to a box shadow in the same rule */
a:focus, button:focus { outline: none; box-shadow: 0 0 0 3px #1a5fb4; }
/* pass: a reset for mouse focus, with :focus-visible for the keyboard */
nav a:focus { outline: none; }
nav a:focus-visible { outline: 3px solid #1a5fb4; }
</style>
</head>
<body>
<a class="skip" href="#main">Skip to main content</a>
<header><p>Example Bank</p></header>
<nav aria-label="Main">
<a href="/" aria-current="page">Home</a>
<a href="/accounts">Accounts</a>
</nav>
<main id="main">
<h1>Focus outline replaced</h1>
<p>Review your recent payments or <a href="/statements">download a statement</a>.</p>
<button type="button">Show more payments</button>
</main>
<footer><p>Example Bank footer</p></footer>
</body>
</html>This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.