2.4.7 Focus Visible

WCAG 2.2 · 2.4.7 AA Operable

This criterion belongs to Principle 2, Operable, under Guideline 2.4 Navigable. It is a long-standing Level AA requirement carried forward unchanged into WCAG 2.2.

What it requires

Any user interface that can be operated by keyboard must have a visible indication of which element currently has keyboard focus. As the user tabs through links, buttons, fields, and other controls, the element with focus must show a distinguishable focus indicator (such as an outline or ring) so its location is always apparent. The criterion does not mandate a specific style or contrast — only that a visible focus indicator exists. (WCAG 2.2 adds 2.4.13 Focus Appearance to govern the indicator's size and contrast; 2.4.7 governs only its presence.)

  • Keyboard-only users — people with motor disabilities or who use switch devices and cannot use a mouse; without a visible indicator they cannot tell where they are on the page.
  • Sighted users with low vision or cognitive disabilities who rely on a clear focus position to track and orient themselves.
  • Power users navigating by keyboard for speed, who lose their place when focus is invisible.

How to detect it

Checks for Focus Visible
Method What to do Failure signal
Keyboard tab-through Press Tab / Shift+Tab through every interactive control. Focus moves but no visible indicator appears on one or more controls.
CSS inspection Look for outline: 0 / outline: none with no replacement. Focus styling removed without a visible substitute.
Custom controls Tab to scripted widgets (menus, tabs, custom buttons). The roving-focus item shows no visible focus state.
Zoom / high contrast Re-check at 200% zoom and in a high-contrast theme. Indicator disappears against the changed background.
Automated tools Run axe / Lighthouse. Limited help — tools flag outline:none heuristically but cannot confirm a visible indicator; manual keyboard testing is required.

How to fix it

  1. Never remove the default focus indicator without providing a clearly visible replacement.
  2. Prefer :focus-visible so the indicator shows for keyboard users without appearing on mouse clicks.
  3. Use a high-contrast outline (with outline-offset) rather than relying on colour change alone.
  4. Give custom and scripted widgets the same visible focus treatment as native controls.
  5. Verify the indicator survives every theme, zoom level, and background it can appear on.
:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 2px;
}

Copy-paste tests

Automated coverage

There is no fully automated axe-core rule that confirms Focus Visible: tools can flag outline:none heuristically but cannot verify that a visible focus indicator actually appears. This criterion needs manual review — use the console check and the keyboard steps below.

Run this in the browser console

console — focus-visible-audit.js
// READ-ONLY: lists focusable controls that suppress their focus outline.
const focusable = document.querySelectorAll(
  'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const suspects = [...focusable].filter(el => {
  const s = getComputedStyle(el);
  const noOutline = s.outlineStyle === 'none' || parseFloat(s.outlineWidth) === 0;
  const noRing = s.boxShadow === 'none';
  return noOutline && noRing;
});
console.log('Focusable controls:', focusable.length, '| suspects:', suspects.length);
console.table(suspects.map(el => ({
  tag: el.tagName.toLowerCase(),
  text: (el.textContent || '').trim().slice(0, 40),
  outline: getComputedStyle(el).outline
})));
suspects.forEach(el => { el.style.outline = '2px dashed magenta'; }); // visual only, not saved

What to check manually: Tab through every control and confirm a visible indicator appears on each — including custom/scripted widgets — and that it stays visible at 200% zoom and in a high-contrast theme. The script cannot confirm a :focus-visible or box-shadow ring is actually perceivable.