You can remove the browser’s default blue focus outline and still pass WCAG — as long as you replace it with a custom indicator that has at least 3:1 contrast against the colors around it, and you scope it to :focus-visible so mouse users never see it. That is the entire peace treaty between your designer and your accessibility checklist. This post gives you five replacement styles that hold up on both sides, with the contrast math already done.
Why is outline: none in your stylesheet?
Because at some point, someone clicked a button, saw a ring glowing around it afterward, and said “get rid of that.” That reaction wasn’t unreasonable. The old :focus styles fired on mouse clicks too, looked different in every browser, and rarely matched the brand. So a one-line fix went in — outline: none — and it shipped.
The problem is what that line does to people who don’t use a mouse. The focus indicator is the only way a keyboard user — someone with a tremor, a repetitive strain injury, a power user, a person testing your site before filing a demand letter — can see where they are on the page. As accessibility consultant Sara Soueidan puts it, “the focus indicator is to keyboard users what the mouse cursor is to mouse users.” Delete it with nothing in its place and every Tab press moves an invisible cursor. You can confirm this on your own site in minutes with our 10-minute keyboard test.
What do the rules actually require?
Less than most designers fear. Three WCAG success criteria cover focus indicators, and only two apply at the Level AA that US courts and the DOJ reference:
- 2.4.7 Focus Visible (Level AA): “Any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible,” per the W3C’s normative text. Some indicator must exist. It says nothing about it being blue, thick, or ugly.
- 1.4.11 Non-text Contrast (Level AA): the indicator needs a contrast ratio of at least 3:1 against adjacent colors. The W3C’s guidance notes that since most focus indicators sit outside the component, “it needs to contrast with the background that the component is on” — the page, not the button.
- 2.4.13 Focus Appearance (Level AAA, new in WCAG 2.2): the indicator should be at least as large as a 2 CSS pixel thick perimeter of the component, with 3:1 contrast between the focused and unfocused states. You are not required to meet AAA, but it’s a cheap target to hit and a good spec to hand a designer.
So the design brief is genuinely short: any color, any shape, roughly 2px or thicker, 3:1 against what’s behind it. That leaves enormous room for something on-brand.
How does :focus-visible keep mouse users from seeing the ring?
:focus-visible only matches when the browser’s heuristics decide the user needs to see focus — in practice, keyboard navigation — while plain :focus matches on every click. MDN’s documentation frames the payoff precisely: it “allows authors to change the appearance of the focus indicator without changing when the focus indicator appears.”
This is the clause that ends the argument. The scenario your designer objected to — a ring lingering on a button after a mouse click — simply stops happening. Keyboard users get a clear indicator; pointer users get a clean interface. And there’s no browser-support excuse left: MDN lists :focus-visible as Baseline, available in all major browsers since March 2022.
/* One rule, site-wide, as a floor */
:focus-visible {
outline: 3px solid #1E3A8A;
outline-offset: 2px;
}
Which focus styles pass AA and still look designed?
Here are five patterns we’d happily ship on a client site. Each passes 1.4.11’s 3:1 requirement on the background stated, and every ratio below was computed with the WCAG contrast formula.
1. The offset brand ring
:focus-visible {
outline: 3px solid #2563EB;
outline-offset: 2px;
}
The outline-offset adds a 2px air gap between the element and the ring, so it reads as a deliberate halo instead of a clamp. On a white page, #2563EB measures 5.2:1 — a comfortable pass. Swap in your own brand color after checking it in our contrast checker.
2. The two-tone ring that works on any background
:focus-visible {
outline: 3px solid #111827;
box-shadow: 0 0 0 6px #FFFFFF;
}
This is Sara Soueidan’s “universal” indicator: a dark ring wrapped in a white one. On light backgrounds the dark ring carries the contrast (17.7:1 on white); on dark backgrounds the white ring does (17.7:1 on #111827). One rule covers your hero, your footer, and your dark-mode toggle.
3. The rounded shadow ring
:focus-visible {
outline: 3px solid transparent;
box-shadow: 0 0 0 3px #0F766E;
}
box-shadow follows border-radius, so the ring hugs pill buttons and rounded cards instead of boxing them. The transparent outline is not decoration — Soueidan notes that the outline property “is retained in forced colors modes (like Windows High Contrast Mode) where other visual styles like box-shadows and background colors are overridden by system colors.” Without it, high-contrast-mode users lose the indicator entirely. #0F766E on white: 5.5:1.
4. The zero-new-colors ring
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 3px;
}
currentColor draws the ring in the element’s own text color. If your text already passes the 4.5:1 body-text minimum, the ring automatically clears 3:1 — no new hex codes enter the palette, which is often the fastest “yes” you’ll get from a designer guarding a tight system like the ones in our accessible brand palette guide.
5. The inverted fill
.btn:focus-visible {
outline: 3px solid transparent;
background: #FFFFFF;
color: #2563EB;
box-shadow: inset 0 0 0 2px #2563EB;
}
For a solid #2563EB button on a white page, flipping the fill on focus changes those pixels by 5.2:1 — a state change even peripheral vision catches, with no ring outside the silhouette. Keep the inset shadow so the button keeps an edge, and keep the transparent outline for forced-colors mode. This one needs per-component math, so treat it as the premium option, not the default.
The contrast math, done for you
Ratios computed with the WCAG relative-luminance formula. “Pass” means it meets the 3:1 minimum in 1.4.11 for a ring drawn on that background.
| Ring color | On white #FFFFFF | Verdict |
|---|---|---|
Black #000000 | 21.0:1 | Pass |
Navy #1E3A8A | 10.4:1 | Pass |
Violet #7C3AED | 5.7:1 | Pass |
Teal #0F766E | 5.5:1 | Pass |
Blue #2563EB | 5.2:1 | Pass |
Red #DC2626 | 4.8:1 | Pass |
Light blue #4D90FE | 3.1:1 | Pass — barely |
Amber #F59E0B | 2.2:1 | Fail |
Sky #38BDF8 | 2.1:1 | Fail |
Gray #CCCCCC | 1.6:1 | Fail |
White #FFFFFF on dark #111827 | 17.7:1 | Pass |
Two patterns worth noticing. Saturated mid-tones and darks nearly always pass on white. The colors designers instinctively reach for to make a ring “subtle” — pale grays, light blues, yellows — are exactly the ones that fail. Subtle and visible pull in opposite directions here; the offset gap in style #1 is how you get elegance without sacrificing contrast.
What does before-and-after look like on a real button?
Take a typical primary button: white text on #2563EB, 8px radius, sitting on a white page.
Before — the line that’s probably live right now:
.btn:focus { outline: none; }
Tab to this button and nothing changes. A keyboard user cannot tell it’s selected. That’s a 2.4.7 failure an auditor — or a plaintiff’s tester running through your checkout flow — finds in the first thirty seconds.
After — the replacement:
.btn:focus {
outline: none; /* kill the inconsistent default */
}
.btn:focus-visible {
outline: 3px solid transparent; /* survives forced colors */
box-shadow: 0 0 0 2px #FFFFFF, /* gap between button and ring */
0 0 0 5px #1E3A8A; /* navy ring: 10.4:1 on white */
}
Click the button with a mouse: nothing appears. Tab to it: a crisp navy ring with a clean white gap, matching the button’s rounded corners. Same brand, same silhouette, one extra visual state — designed on purpose instead of inherited from a browser default.
Ship checklist
- Search your CSS for
outline: noneandoutline: 0. Every match either gets a:focus-visiblereplacement or gets deleted. - Add one global
:focus-visiblerule as a floor, then override per component only where the design demands it. - Check the ring color against the page background — 3:1 minimum, and remember it’s the background around the element that counts. Our contrast checker does the math.
- Tab through every page template — nav, forms, cards, footer — following the 10-minute keyboard test. The ring must be visible at every single stop.
- Check your dark sections. A navy ring that passes on white disappears in a navy footer. Style #2 above, or a per-section override, closes that gap.
A visible, on-brand focus indicator is one of the highest-leverage fixes in accessibility: one stylesheet change, every keyboard user on every page. It’s also one of the first things we look for when we remediate a site’s code, because a missing focus style almost always travels with deeper keyboard issues — broken tab order, traps, unreachable menus — that no widget or overlay can patch from the outside.
Want to know how many elements on your site currently have no visible focus style? Start with a free scan.