Focus state design: an indicator visible everywhere that fits the style
Keyboard users find their place on a page through the focus indicator, so removing it is like hiding the mouse pointer. Style it instead: a 2 to 3px outline in a colour with at least 3:1 contrast against the background, offset slightly from the element, shown with :focus-visible, and checked on every surface the page uses.
Who relies on focus
Not everyone uses a mouse. People with motor impairments, repetitive strain injuries or tremors often navigate with a keyboard, switch device or voice control. Screen reader users move focus with keys. Plenty of people without any impairment use Tab to jump through a form. In every case, the focus indicator is the only thing telling them which element will respond if they press Enter.
Browsers draw a default focus ring, and for years the most common line in website stylesheets was the one that removed it, because designers found the ring ugly on mouse clicks. The result was sites that were literally unusable without a mouse. Good focus state design keeps the indicator and makes it belong.
:focus or :focus-visible
The :focus selector matches whenever an element has focus, including after a mouse click on a button. :focus-visible matches only when the browser judges that showing focus is helpful, chiefly when the person is using a keyboard. Text inputs show it on click too, since typing follows. Styling :focus-visible gives keyboard users a clear ring without flashing one at mouse users, which removes the old reason for deleting it.
A sensible base: :focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }. In current major browsers, outlines follow the element's rounded corners, so the ring hugs pill buttons and rounded cards rather than drawing a rectangle around them.
Making it visible on every background
The ring that shows clearly on a white page can vanish on a dark footer, a coloured button or a photograph. Check it on every surface: ground, cards, the action-coloured button itself, dark sections and any image with text over it.
- Offset the outline a few pixels so it sits on the page background rather than on the element's own fill. A blue ring directly on a blue button is invisible; offset, it sits against the page.
- Use a two-tone ring for pages with mixed backgrounds: a dark outline with a light inner ring (or the reverse), for example an outline plus a
box-shadowof the opposite colour. One of the two always contrasts. - Switch the colour per section with a custom property, so dark sections set
--focusto a light value. - Don't rely on colour change alone. Turning a link a slightly different shade on focus is easy to miss. Add an outline or a thick underline.
What WCAG 2.2 asks
| Criterion | Level | In short |
|---|---|---|
| 2.4.7 Focus Visible | AA | Keyboard focus must have a visible indicator. |
| 2.4.11 Focus Not Obscured (Minimum) | AA | The focused element can't be entirely hidden by other content, such as a sticky header or cookie banner. |
| 2.4.13 Focus Appearance | AAA | The indicator is at least as large as a 2px outline around the element and changes contrast by at least 3:1 between focused and unfocused states. |
| 1.4.11 Non-text Contrast | AA | Visual information needed to identify a state, focus included, needs 3:1 against adjacent colours. |
The full text is in the W3C's Understanding Focus Appearance. A 2px solid outline with good contrast and a small offset meets the AAA guidance in most layouts, which makes it a good default even if AA is your target.
Mistakes to avoid
outline: nonewith nothing to replace it, still common in resets and component libraries.- A shadow-only indicator. In Windows high-contrast (forced colours) mode, shadows are removed. If you use a shadow, add
outline: 2px solid transparenttoo; forced colours mode turns that transparent outline visible. - Focus hidden under a sticky header. When tabbing scrolls an element into view beneath a fixed header, it's obscured.
scroll-padding-topset to the header's height fixes it. - Clipped rings.
overflow: hiddenon a container can cut the outline off. Use an inset outline or adjust the container. - Custom controls that can't take focus at all. A clickable
divnever shows a ring because it never receives focus. Use real buttons and links.
Fitting it to the style
A focus ring doesn't have to look like the browser default. In a brutalist design it can be a thick black outline with no offset; in a soft, rounded system a ring in the action colour that follows the curve; in a Swiss layout a sharp rectangle. What it can't be is subtle. Treat it as part of the visual language, designed with the same care as the hover state, which it should usually mirror. Hover effects for websites covers that pairing.
Anticode's focus styles
Since 23 October 2026, Anticode's design gate blocks publishing any page without a visible keyboard focus style. Every design system sets one: on design-engine pages it's a 2px outline in the system's action colour, offset 3px from the element, applied with :focus-visible. Because the action colour has separate light- and dark-theme values, the ring changes with the theme.
The gate checks that a focus style exists, not that it's visible on every surface. If you add a section in a colour close to the action colour, or put a button over a photograph, tab through it yourself and check the ring still shows.
Questions people ask
Is it OK to remove the focus outline?
Only if you replace it with something at least as visible. Removing it outright makes the page unusable for keyboard users and fails WCAG 2.4.7.
Should I use :focus or :focus-visible?
Use :focus-visible for the visible ring. It shows for keyboard users and text inputs without appearing on every mouse click.
What colour should a focus outline be?
Often the action colour, provided it reaches 3:1 against every background it appears on. Use a two-tone ring if one colour can't manage that.