Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.
CSSHigh

Provide visible custom focus indicators

Ensure all interactive elements have a clearly visible focus indicator for keyboard navigation — never just remove the default outline without providing a better alternative.

Utilities
Quick take
Typical fix time 15 min
  • Never use outline: none or outline: 0 without a visible :focus-visible replacement
  • Use :focus-visible instead of :focus to show indicators only during keyboard navigation
  • Focus indicators must have 3:1 contrast ratio against adjacent colors (WCAG 2.2)
  • Provide at least 2px solid outline with an offset for a high-quality focus ring
  • If a focus ring is drawn with pseudo-elements, verify it is anchored to the correct positioned element and not clipped by `overflow: hidden`
  • If the component uses a stretched-link pattern, verify the visible focus ring follows the actual interactive element rather than a parent wrapper by accident
Why it matters: Users who navigate by keyboard (people with motor disabilities, power users, people in assistive technology contexts) rely entirely on focus indicators to know where they are on the page. Removing outlines without replacement makes an entire site unusable for keyboard users. WCAG 2.4.7 requires a visible focus indicator, and WCAG 2.4.13 defines a stronger size-and-contrast target for custom indicators.

Rule Details

Focus indicators are essential for keyboard navigation. Never remove them without providing a better alternative.

Code Example

/* ❌ Removes focus indicator — keyboard users can't see where they are */
* { outline: none; }
*:focus { outline: none; }
button:focus { outline: 0; }

Why It Matters

Users who navigate by keyboard (people with motor disabilities, power users, people in assistive technology contexts) rely entirely on focus indicators to know where they are on the page. Removing outlines without replacement makes an entire site unusable for keyboard users. WCAG 2.4.7 requires a visible focus indicator, and WCAG 2.4.13 defines a stronger size-and-contrast target for custom indicators.

:focus-visible (The Right Approach)

:focus-visible shows focus indicators only during keyboard navigation, not when clicking with a mouse. This satisfies both aesthetics (no ring on click) and accessibility (ring on keyboard).

/* ❌ Old approach: shows ring on mouse click too */
button:focus {
  outline: 2px solid blue;
}
 
/* ✅ Modern approach: only during keyboard navigation */
button:focus { outline: none; } /* Hide default on mouse click */
button:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

A High-Quality Focus Style

/* Base reset for all browsers */
*:focus {
  outline: none;
}
 
/* Visible focus only for keyboard navigation */
*:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 3px;
  border-radius: 3px;  /* Optional: match element border-radius */
}

Component-Specific Focus Rings

/* Inset ring for elements where outline-offset would overlap content */
.button {
  position: relative;
}
 
.button:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
 
/* Dark surface: use a light ring */
.dark-nav .nav-link:focus-visible {
  outline-color: white;
}
 
/* For inputs: border change instead of outline */
.input:focus-visible {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgb(37 99 235 / 0.25);
}
/* Visually hidden but visible on focus */
.skip-link {
  position: absolute;
  top: -100%;
  left: 1rem;
  padding: 0.5rem 1rem;
  background: var(--color-primary);
  color: white;
  text-decoration: none;
  border-radius: 0 0 0.5rem 0.5rem;
  z-index: 1000;
}
 
.skip-link:focus {
  top: 0;
}

WCAG 2.2 Requirements

WCAG 2.2 Success Criterion 2.4.11 (Focus Appearance, AA) requires:

  • Focus indicator area of at least the perimeter of the unfocused component times 2 CSS pixels
  • Contrast ratio of at least 3:1 between focused and unfocused states
  • At least 3:1 contrast against adjacent colors

Verification

  1. Inspect the rendered UI at the breakpoints and interaction states affected by the rule.
  2. Confirm the computed styles match the intended fix in DevTools.
  3. Test at least one mobile and one desktop viewport before shipping.
  4. If the rule affects motion, contrast, or layout stability, verify those user-facing outcomes directly.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Find all instances of outline: none, outline: 0, or :focus { outline: none } in this CSS. Check if they provide an alternative visible focus indicator. If the replacement uses pseudo-elements, also verify the ring cannot be clipped or misplaced by overflow or missing positioning context.

Fix

Auto-fix issues

Replace outline: none on :focus with :focus-visible styles that provide a clearly visible custom focus ring with appropriate contrast.

Explain

Learn more

Explain the difference between :focus and :focus-visible, why focus styles matter for accessibility, and how to design an accessible focus ring.

Review

Code review

Review stylesheets, component styles, and responsive states related to Provide visible custom focus indicators. Flag exact selectors, declarations, or breakpoints that violate the rule in the rendered UI.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Rules that often go hand-in-hand with this one.

Provide sufficient touch target size

Interactive elements must have large enough touch targets so users with motor impairments can activate them accurately on touchscreen devices.

Accessibility
Enable keyboard navigation for all elements

All interactive elements are accessible via keyboard with logical focus order and hidden elements excluded from tab sequence.

Accessibility

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385