Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

:focus-visible Ends the outline: none Wars

C
Carlo Fontanos
· 2 min read

For years, web accessibility had a recurring tragedy in three acts. Act one: browser draws focus ring when you click a button. Act two: designer says it's ugly, developer writes *:focus { outline: none }. Act three: every keyboard user loses the ability to see where they are on the page.

The root problem was that :focus can't tell how focus arrived. Clicking focuses, tabbing focuses - same pseudo-class. :focus-visible fixes exactly that:

/* Remove the ring ONLY when the browser deems it unnecessary (mouse/touch) */
:focus:not(:focus-visible) {
    outline: none;
}

/* And make the keyboard ring genuinely good */
:focus-visible {
    outline: 2px solid #4f46e5;
    outline-offset: 2px;
    border-radius: inherit;
}

Click a button: no ring. Tab to it: clear ring. Both audiences satisfied, no JavaScript, no focus-trap hacks.

When does it match?

The heuristic is the browser's, and it's smarter than "keyboard vs mouse":

  • Tab / Shift-Tab focus: matches.
  • Mouse click on a button: doesn't match.
  • Mouse click on a text input: matches anyway - because you're about to type, the browser treats it as keyboard interaction. This surprises people, but it's the right call.
  • Focus moved by script right after a keypress: generally matches.

You may not need the :not() rule at all

Here's the part that's genuinely little-known: modern browsers' default focus ring already uses :focus-visible internally. If you never wrote outline: none in the first place, clicking buttons hasn't shown rings for years. The cleanup rule exists for codebases that carry old resets - which is most of them. Audit for outline: none, replace with the pair above, done.

Styling notes from practice

.btn:focus-visible {
    outline: 2px solid currentColor;   /* adapts to the button's own color */
    outline-offset: 2px;
}
  • Prefer outline over box-shadow for rings: outline doesn't affect layout, follows border-radius in all modern engines now, and survives overflow clipping better.
  • outline-offset creates the gap that makes rings look designed instead of default.
  • Test with a real Tab-through of your page. It takes ninety seconds and instantly reveals whether your interactive elements are reachable and visible - the cheapest accessibility audit that exists.

Support: every browser since 2022. This belongs in the same family as accent-color - platform features that let you stop choosing between design taste and accessibility.

C
Written by Carlo Fontanos

Full-stack web developer sharing practical tutorials and building tools that ship.

Got something on your mind?

My inbox is open - no forms disappearing into the void here.

  • Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
  • Hire me for a project Have something custom in mind? Let's talk scope and timelines.
  • Product support Bought something here? I'll help you get it running.

I usually reply within 1-2 business days.

Message sent!

Your details are only used to reply to you.

Keep reading