C

CSS Handbook

Clean • Professional

Understanding CSS Focus States

2 minute

Understanding CSS Focus States: :focus vs :focus-visible

Focus states in CSS help make websites accessible and user-friendly, especially for keyboard users and those using assistive technologies. The :focus and :focus-visible pseudo-classes allow developers to style elements when they are active, improving usability and accessibility.

A focus state occurs when an interactive element—like a button, link, or input—is active, usually through Tab key navigation or a mouse click.

CSS provides two main pseudo-classes for focus states: :focus and :focus-visible.

:focus vs :focus-visible

:focus Pseudo-Class

The :focus pseudo-class styles an element whenever it gets focus, whether by mouse, keyboard, touch, or JavaScript. It’s commonly used for buttons, inputs, and links. Because it applies to all focus events, it can sometimes look distracting for mouse users. Always keep a clear focus style, rather than removing it, to ensure accessibility.

Example:

button:focus {
  outline: 3px solid #007BFF; /* Universal focus indicator */
  outline-offset: 2px;
}

:focus-visible Pseudo-Class

The :focus-visible pseudo-class styles an element only when it’s meaningful, usually for keyboard navigation or assistive technology users. Mouse clicks typically don’t trigger it, keeping the interface cleaner. It ensures keyboard users see a clear focus indicator without cluttering the UI for mouse users.

Example:

button:focus-visible {
  outline: 3px solid #FF6200; /* Keyboard focus indicator */
  outline-offset: 3px;
  box-shadow: 0 0 5px rgba(255, 98, 0, 0.5);
}

Key Differences:

Feature:focus:focus-visible
TriggerAll focus events (mouse, keyboard, touch, script)Primarily keyboard or assistive tech focus
Use CaseGeneral focus stylingKeyboard-specific, accessibility-first styling
Visual ImpactCan be distracting on mouse clicksReduces clutter, appears only when needed
Browser SupportUniversalModern browsers (2020+)
Accessibility RiskHigh if default styles removedLow; respects browser heuristics

Example 1: Accessible Login Form

<a href="#main-content" class="skip-link">Skip to Main Content</a>
<form>
  <div class="form-group">
    <label for="username">Username</label>
    <input type="text" id="username" placeholder="Enter username">
  </div>
  <div class="form-group">
    <label for="password">Password</label>
    <input type="password" id="password" placeholder="Enter password">
  </div>
  <button type="submit">Log In</button>
</form>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #1a73e8;
  color: white;
  padding: 8px;
  z-index: 100;
}
.skip-link:focus { top: 0; }

input, button {
  padding: 10px;
  font-size: 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
  width: 100%;
  box-sizing: border-box;
}

/* Focus Styles */
input:focus, button:focus {
  outline: 2px solid #1a73e8; /* Fallback */
}
input:focus-visible, button:focus-visible {
  outline: 3px solid #ff6200;
  outline-offset: 3px;
  box-shadow: 0 0 5px rgba(255, 98, 0, 0.5);
}
button { background: #1a73e8; color: white; border: none; cursor: pointer; }
button:hover { background: #1557b0; }

Example 2: Keyboard-Friendly Navigation Menu

<nav>
  <ul>
    <li><a href="#home">Home</a></li>
    <li><a href="#services">Services</a></li>
    <li><a href="#contact">Contact</a></li>
  </ul>
</nav>
nav { background: #333; padding: 10px; }
ul { list-style: none; display: flex; gap: 15px; margin: 0; padding: 0; }
li a { color: white; text-decoration: none; padding: 10px 15px; border-radius: 4px; display: block; }
li a:hover { background: #555; }
li a:focus { outline: 2px solid #fff; outline-offset: 2px; }
li a:focus-visible { outline: 3px solid #ffeb3b; outline-offset: 3px; background: #444; }

 

Article 0 of 0