focus-visible: keeping a visible keyboard focus ring
Removing the focus outline leaves keyboard users with no idea where they are. squirrel flags outline:none with no :focus-visible fallback.
What a focus indicator is
When a keyboard user tabs through a page the browser draws a ring around the focused element. outline: none deletes it, and without a replacement the user is navigating blind. WCAG success criterion 2.4.7 Focus Visible, Level AA, requires that the indicator exist.
:focus-visible is the modern way to restyle it. The browser decides when an indicator is warranted rather than matching every focus event, so in practice a keyboard user gets the ring and someone clicking a button does not. The heuristic is the browser’s, not the page’s: text inputs generally match on a mouse click too, and a user preference can force the indicator on everywhere.
What squirrel checks
This rule scans the page source as text, covering inline <style> blocks and style attributes. Rules in a linked stylesheet are not fetched, so they are invisible to it. Severity is warning.
focus-outline-globalfails when the source contains a universal-selector rule that removes the outline, matching the shape* { ... outline: none }oroutline: 0. Report message:Global outline removal detected, with the value* { outline: none } removes focus for all elements.focus-outlinewarns when no global removal pattern matched,outline: noneoroutline: 0appears anywhere, and:focus-visibledoes not. The two branches are exclusive, so a page with global removal never produces this warning. Report message:outline:none found - ensure alternative focus styles exist, with the valueConsider using :focus-visible for custom focus styles.focus-modernpasses when:focus-visibleor:focus-withinappears, with the messageModern focus selectors in useand the matched selector as its value.focus-visiblereturns info withFocus styles not analyzed (requires CSS inspection)when none of the above matched.
How to fix it
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
:focus:not(:focus-visible) {
outline: none;
}Keep both rules together: the first draws the ring where the browser judges an indicator useful, the second removes the default ring everywhere else. Between them nobody navigating by keyboard is left without an indicator.
Because the match is textual, outline: none inside a comment or a minified vendor bundle is still reported. The reverse is more common: a site whose focus styles live in an external stylesheet returns info even when the styles are correct.
| Rule ID | a11y/focus-visible |
| Category | Accessibility |
| Scope | Per-page |
| Severity | warning |
| Weight | 5/10 |
Enable / disable
Disable this rule
[rules]
disable = ["a11y/focus-visible"]Disable all Accessibility rules
[rules]
disable = ["a11y/*"]Enable only this rule
[rules]
enable = ["a11y/focus-visible"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- a11y/tabindex: positive
tabindexvalues that scramble the order the ring moves in. - a11y/aria-hidden-focus: elements that take focus while hidden from assistive technology.
- a11y/skip-link: letting keyboard users jump past repeated navigation.
- a11y/color-contrast: text against its background, the contrast check squirrel does run. It does not measure the ring itself.
Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.
References
- :focus-visible, MDN
- Understanding SC 2.4.7 Focus Visible, W3C
- F78: Failure due to styling out the focus indicator, W3C
Check your site
Run squirrel audit https://example.com and open the Accessibility section of the report. Global outline removal is reported first, since it affects every control. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.