Removing the default outline requires a replacement
Aliases: outline none · custom focus · CSS reset focus
What it is
Browsers draw a default outline on focusable controls because the keyboard has no pointer to watch. A reset that sets outline: none or outline: 0 removes that shared cue. A custom indicator may replace it. Removal without replacement is not allowed. The replacement must appear on keyboard focus; a hover fill or a mouse-down state is not a replacement. Whether the ring is bright enough on every ground is the previous leaf. This one is the fact of whether any indicator remains once the default is gone.
Why it happens
User-agent style is the floor for keyboard visibility. Global resets, component libraries chasing a “clean” look, and wiping :focus together with :focus-visible erase that floor. :focus { outline: none } also kills residual focus after a click, so Tab has no ring either. Clearing outline only inside :focus-visible without writing a new stroke or inner glow leaves the keyboard path equally blind.
A box-shadow or fill change can be a replacement if it is bound to a keyboard-perceivable pseudo-class and actually paints — a rule in the docs overridden by a later reset is no replacement. Custom controls (div tabindex="0") never had a button-like user-agent outline; wiping defaults without adding one produces the defect in sheets.
Studying it
Search CSS for outline:\s*(none|0) and equivalent outline-width: 0. For each hit, check whether the same selector or :focus-visible paints a visible replacement. Keyboard-walk the site against a user-agent-only page.
Independent variables: whether outline is removed, whether a replacement exists, whether it is bound to :focus or :focus-visible.
Dependent variables: whether any visible mark exists at a keyboard stop, whether a mark wrongly appears after a mouse click, times a reset overrides the replacement.
Include a blank page that only loads the popular reset: the defect often lives in the base, not in product CSS.
Where it stops holding
Hiding focus after pointer activation while still showing it for keyboard is legitimate :focus-visible use, not “remove without replace.” Non-focusable decoration should not have focus style. Some mobile WebViews already ship a weak user-agent outline, which is more reason not to strip it. Forced-colors mode may repaint the outline; a custom replacement must yield or adapt, or the user gets two indicators — or none.
Applying it
- Ban
outline: none/0without a paired rule. The same place that removes the default must write a:focus-visiblereplacement. - Bind the replacement — stroke, two-tone ring, or a thick enough
box-shadow— to a keyboard-visible pseudo-class, not to:hover. - Treat custom focusable controls like native ones: they have no user-agent outline, so draw the replacement from day one.
- Verify: search the tree for outline-off rules and open the matching focus style. Hide the pointer and Tab; any stop with no mark fails. Temporarily disable site CSS and leave user-agent style to confirm the gap came from the reset, not from a browser that never drew.