No Login Data Private Local Save

:focus‑visible Tester - Online Keyboard‑Only Focus Ring

8
0
0
0

🎯 :focus-visible Tester

Test and compare :focus-visible vs :focus pseudo-classes in real time. Discover how browsers intelligently show focus rings only when you need them — for keyboard navigation, not mouse clicks.

Keyboard Navigation Mouse Interaction Accessibility CSS Pseudo-Class
Try this: Click each button with your mouse, then press Tab on your keyboard to navigate. Notice the difference in focus ring appearance!

:focus-visible

Keyboard Only*
Buttons
Form Inputs (browser may show ring on click too)
Checkbox & Radio
Custom Focusable Element tabindex="0"
📦 Focusable Card (tabindex=0)

:focus

Always Visible
Buttons
Form Inputs
Checkbox & Radio
Custom Focusable Element tabindex="0"
📦 Focusable Card (tabindex=0)
Last Interaction: Idle
Focused Element:
Keyboard Focuses: 0 Mouse Focuses: 0
Browser heuristic: For text input fields (<input>, <textarea>, <select>), most browsers also match :focus-visible on mouse click — because showing a focus indicator on text fields is always helpful for usability. Buttons and links typically only match :focus-visible via keyboard navigation.
CSS
/* ✅ Best Practice: Hide default focus, show only for keyboard */
:focus {
  outline: none;
}
:focus-visible {
  outline: 3px solid #3b82f6;
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.25);
  border-radius: 4px;
}

/* For older browsers, use the polyfill: */
/* npm install focus-visible */
/* import 'focus-visible'; */

Frequently Asked Questions

:focus-visible is a CSS pseudo-class that applies styles only when the browser determines that a focus indicator should be visible. It represents the browser's best guess about when the user really needs to see a focus ring — typically when navigating via keyboard (Tab, arrow keys) rather than mouse click or touch.

Introduced by the CSS Selectors Level 4 specification, it helps solve a long-standing UX problem: focus rings are essential for keyboard users but visually annoying for mouse users.

:focus — matches any element receiving focus, regardless of input modality (mouse, keyboard, touch, or programmatic). The focus ring appears every single time.

:focus-visible — matches only when the browser believes the user needs to see the focus indicator. Typically:

  • Keyboard (Tab/arrow keys): ✅ Matches — shows focus ring
  • Mouse click on buttons/links: ❌ Does not match — no focus ring
  • Mouse click on text inputs: ✅ Usually matches — helpful for typing

Native support is excellent across all modern browsers:

BrowserVersionSupport
Chrome86+✅ Full
Firefox85+✅ Full
Safari15.4+✅ Full
Edge86+✅ Full
Samsung Internet16+✅ Full
iOS Safari15.4+⚠️ Partial

For older browser support, use the official focus-visible polyfill from WICG.

The polyfill adds a .focus-visible class to focused elements when the browser would have matched :focus-visible. Here's how to use it:

npm install focus-visible
// In your JS entry file:
import 'focus-visible';

/* In your CSS, use both to cover all browsers: */
:focus { outline: none; }
:focus-visible,
.focus-visible {
  outline: 3px solid #3b82f6;
  outline-offset: 2px;
}

The polyfill is lightweight (~2KB) and works by simulating the browser's heuristic using JavaScript event listeners for keyboard and mouse input.

This is expected browser behavior and part of the specification's heuristic. Browsers determine when to match :focus-visible based on element type and context:

  • Text inputs, textareas, selects: Always show focus indicator — the user needs to know where they're typing.
  • Buttons, links, checkboxes, radios: Only show focus indicator on keyboard navigation — mouse clicks don't need the extra visual noise.
  • Contenteditable elements: Treated like text inputs, usually match on click.

You cannot override this heuristic with CSS alone. If you truly need to suppress focus indicators on text inputs for mouse users, you'd need JavaScript-based solutions (though this is generally not recommended for accessibility reasons).

The recommended best practice combines both pseudo-classes for maximum compatibility and usability:

  1. Remove default focus outline with :focus { outline: none; }
  2. Add a clear, high-contrast focus indicator via :focus-visible
  3. Ensure the focus indicator meets WCAG 2.2 Focus Appearance criteria (minimum 3:1 contrast ratio, at least 2px thick)
  4. Use outline-offset to prevent the focus ring from touching the element edge
  5. Add a fallback using the .focus-visible class with the polyfill for older browsers

❌ Avoid: :focus { outline: none; } without providing an alternative — this breaks keyboard accessibility entirely.

Absolutely! You're not limited to the browser's default outline. Here are some creative approaches:

/* Glowing ring */
:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px #fff, 0 0 0 6px #3b82f6;
  border-radius: 6px;
}

/* Underline indicator */
:focus-visible {
  outline: none;
  border-bottom: 3px solid #3b82f6;
  padding-bottom: 2px;
}

/* Inset ring */
:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 3px #3b82f6;
}

Just ensure the indicator is clearly visible and meets contrast requirements. The demo on this page uses a blue box-shadow ring for :focus-visible and a red one for :focus to clearly differentiate them.

:focus-visible is a crucial tool for accessibility because it:

  • Preserves keyboard navigation cues — screen reader users, motor-impaired users, and power users who rely on keyboard navigation always see where they are on the page.
  • Reduces visual clutter for mouse users, making designers happy without sacrificing accessibility.
  • Satisfies WCAG Success Criterion 2.4.7 (Focus Visible) — ensuring there's always a visible focus indicator for keyboard users.
  • Supports WCAG 2.2 — the new Focus Appearance criterion (Level AAA) requires a minimum focus indicator size and contrast ratio.

Never use :focus { outline: none; } alone without providing a :focus-visible alternative — this creates an accessibility barrier for keyboard-only users.