Color & Contrast

Focus Indicator Styling

12 min read

Focus Indicator Best Practices

Focus indicators are essential for keyboard navigation, they show users where they are on the page. Unfortunately, many websites remove or hide focus indicators, creating significant accessibility barriers. This guide explains how to create focus indicators that are both accessible and aesthetically pleasing.

Why Focus Indicators Matter

Focus indicators serve several critical functions:

  1. Orientation: Users know which element is currently active
  2. Navigation: Tracking movement through the page
  3. Interaction Confirmation: Visual feedback that an element received focus
  4. Cognitive Support: Reduces mental load for users

WCAG Requirements

WCAG 2.4.7 (Level AA): Focus is visible

WCAG 2.4.11 (Level AAA): Focus appearance (contrast requirements)

The 2.4.11 requirements specify:

  • Minimum area: 1 CSS pixel thick outline or equivalent
  • Contrast: 3:1 against adjacent colors
  • Not fully obscured by other content

The Problem with Default Focus

Browser default focus styles vary and can be inconsistent:

css
/* Browser defaults (simplified) */
/* Chrome: Blue outline */
:focus { outline: -webkit-focus-ring-color auto 1px; }

/* Firefox: Dotted outline */
:focus { outline: 1px dotted; }

/* Safari: Blue ring */
:focus { outline: auto 5px -webkit-focus-ring-color; }

Never Do This

The most common accessibility mistake:

css
/* NEVER remove focus without replacement */
:focus {
  outline: none; /* Accessibility violation! */
}

*:focus {
  outline: 0; /* Also bad */
}

Better Approach: Custom Focus Styles

Basic Custom Focus Ring

css
:focus {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

/* For browsers that support :focus-visible */
:focus:not(:focus-visible) {
  outline: none;
}

:focus-visible {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

High-Contrast Focus Ring

css
:focus-visible {
  outline: 3px solid #0066cc;
  outline-offset: 2px;
  box-shadow: 
    0 0 0 4px #ffffff,
    0 0 0 6px #0066cc;
}

Focus Ring That Works on Any Background

css
:focus-visible {
  outline: 2px solid transparent;
  box-shadow: 
    0 0 0 2px #ffffff,
    0 0 0 4px #000000;
}

Component-Specific Focus Styles

Buttons

css
.button:focus-visible {
  outline: none;
  box-shadow: 
    0 0 0 3px var(--background),
    0 0 0 5px var(--ring-color);
}

Input Fields

css
.input:focus {
  outline: none;
  border-color: #0066cc;
  box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.2);
}

Cards and Large Interactive Areas

css
.card:focus-visible {
  outline: none;
  box-shadow: 
    0 4px 12px rgba(0, 0, 0, 0.1),
    0 0 0 3px #0066cc;
}
css
a:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  border-radius: 2px;
}

Focus Indicators in React/Tailwind

jsx
// Tailwind utility classes for focus
<button className="
  focus:outline-none
  focus-visible:ring-2
  focus-visible:ring-blue-500
  focus-visible:ring-offset-2
">
  Click me
</button>

// Custom component with focus management
function FocusableCard({ children, onClick }) {
  return (
    <div
      tabIndex={0}
      role="button"
      onClick={onClick}
      onKeyDown={(e) => e.key === 'Enter' && onClick()}
      className="
        cursor-pointer
        transition-shadow
        focus:outline-none
        focus-visible:ring-2
        focus-visible:ring-primary
        focus-visible:ring-offset-2
      "
    >
      {children}
    </div>
  );
}

Testing Focus Indicators

  1. Tab Through Your Site: Can you always see where focus is?
  1. Check All Backgrounds: Focus visible on light AND dark areas?
  1. Zoom to 400%: Focus indicator still visible?
  1. High Contrast Mode: Focus works in Windows High Contrast?
css
/* Support Windows High Contrast Mode */
@media (forced-colors: active) {
  :focus-visible {
    outline: 3px solid CanvasText;
    outline-offset: 2px;
  }
}

Common Focus Indicator Patterns

Ring Style (Most Common)

css
:focus-visible {
  outline: 2px solid var(--focus-color);
  outline-offset: 2px;
}

Glow Style

css
:focus-visible {
  outline: none;
  box-shadow: 0 0 0 4px rgba(66, 153, 225, 0.5);
}

Underline Style (for inline elements)

css
a:focus-visible {
  outline: none;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}

Focus Management Checklist

  • Focus indicators are visible on all interactive elements
  • Focus style has sufficient contrast (3:1 minimum)
  • Custom focus styles provided (not relying on browser defaults)
  • Focus indicators work on all background colors
  • No outline: none without replacement styles
  • Tested in Windows High Contrast Mode
  • Focus visible at 400% zoom

Was this article helpful?