What We Found When We Tabbed Through Our Own Site
Have you ever tabbed through your own website? We did it on Revix, found multiple broken focus states, and fixed all of them in about an hour with three Claude Code prompts and one token.

Have you ever tabbed through your own website? Mouse away, keyboard only, through every link and button on the page.
We did it on Revix and found multiple broken focus states. What concerned me is who finds a broken one in the wild: the only people who ever hit it are the ones who can't use a mouse at all, exactly the people focus states exist for. Everyone else clicks past it and never knows it's broken.
Four examples of what we found
Nothing paints. The select trigger took focus and looked exactly like its resting state.


It falls through to the browser. Prose links had no rule of their own, so Chrome drew its default blue. It works, and it looks different in every browser.


It sits too tight to read. The switch had an indicator. Drawn flush against a filled 40 by 20 track, it reads as the edge of the track rather than a signal about it. Moving it outside with a two pixel gap is the whole fix.


It lands on the wrong box. Our back link was a block level anchor, so the outline traced the full column width instead of the words you were about to activate.


What the spec asks for
Two of the three arrived with WCAG 2.2, after most focus advice on the web was written.
- 2.4.7 Focus Visible (AA). An indicator exists.
- 2.4.11 Focus Not Obscured (AA, new in 2.2). The focused element is not completely hidden by something else. Sticky headers, cookie banners, and chat widgets fail this one.
- 2.4.13 Focus Appearance (AAA, new in 2.2). At least 2px thick, and at least 3:1 contrast against the same element unfocused.
The prompts
We used Claude Code to find and fix all four in about an hour. Three passes: find, confirm, fix.
Find focus indicators in this repo that will never render.
Search the stylesheets and component files for `outline: none`,
`outline: 0`, and any `outline-none` utility class. For each hit,
check whether the same element has a `:focus-visible` or
`focus-visible:` rule that draws an indicator back.
List the ones with no replacement, grouped by file, and mark which
are design system primitives and which are one-off components.Grep only finds the deletions. It cannot see a rule that exists and paints nothing, so the second pass reads the live page.
Audit the keyboard focus indicators on my local dev server.
Open it in a browser and walk the tab order from the top of the
document. For each element that receives focus, read its computed
style with getComputedStyle and record:
- outline-width, outline-style, outline-color, and box-shadow
- whether any of those actually paints something visible
- the element's own border-radius, so I can see where the indicator
does not follow the shape
- whether an ancestor has overflow hidden or scroll, which would
clip an outset indicator
Use the computed values, not a screenshot. Report every element
where nothing visible paints, every indicator thinner than 2px, and
every one below 3:1 against the element's own background.Fixing each component on its own is how the drift started, so the third pass asks for a token.
Our focus indicators are defined per component, which is why they
have drifted. Consolidate them.
1. Add one `:focus-visible` rule in the base layer, at the lowest
specificity you can write it, so no element falls through to the
browser default. Use a single colour variable, and let the
indicator follow whatever border radius the element already has.
2. Move every component that defines its own indicator onto it.
3. Where a component genuinely cannot use it, keep the exception
and add a one line comment saying why.
Show me the diff before applying it. Do not touch hover or active
states.One token
About ten lines came out. The colour is a neutral grey rather than our brand green, so the ring reads as a system affordance instead of decoration.
@utility focus-ring {
@apply ring-2 ring-inset ring-focus outline-none;
--tw-ring-offset-width: 0px;
}
@layer base {
:focus-visible {
outline: 2px solid var(--focus);
outline-offset: 2px;
}
}
The base rule sits at the lowest specificity we could write, so any component rule still wins and nothing paints two indicators at once. Anything the design system does not style, prose links included, picks it up for free. Two components keep an exception, both because a ring drawn tight to a fill disappears into it: the switch and filled buttons.
What the agent could not see
Claude Code found every deleted outline in seconds, and the browser pass caught the rules that existed but painted nothing. Neither had an opinion on tab order. A page can pass all three criteria and still walk you through its controls in an order nobody would choose.
More teams should run this check. It costs an hour and a few minutes of tabbing through your own site.
Keep reading
- Most Pull Requests Are Already Fixed Before a Human Opens ThemIn July we reviewed 322 pull requests. Developers fixed 96% of the issues they engaged with, usually within minutes of opening the PR. By the time a reviewer looked, there was nothing left to catch.
- How to Write a Great PR Review CommentMost PR comments waste the author's time because they never say what they actually want. Here is the four-part format that fixes that.