Skip to content

CSS :focus-visible vs :focus Styling Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about CSS :focus. We cover key concepts, practical examples, and best practices.

The Problem

The :focus-visible pseudo-class applies focus styles only when the browser determines the focus should be visible (typically keyboard navigation). When :focus is used instead of :focus-visible, focus outlines either show for every click (annoying) or are removed entirely (inaccessible).

Quick Fix

Step 1: Use :focus-visible for keyboard-only focus

/* Wrong — outline shows on every click */
button:focus {
    outline: 2px solid blue;
}

/* Wrong — outline removed entirely (inaccessible) */
button:focus {
    outline: none;
}

/* Right — visible only for keyboard users */
button:focus-visible {
    outline: 2px solid #6366f1;
    outline-offset: 2px;
}

Step 2: Provide fallback for older browsers

/* Wrong — no fallback for :focus-visible support */
button:focus-visible {
    outline: 2px solid blue;
}

/* Right — use @supports with fallback */
button:focus {
    outline: 2px solid blue; /* Fallback for all browsers */
}

@supports (selector(:focus-visible)) {
    button:focus {
        outline: none; /* Remove when :focus-visible is supported */
    }
    button:focus-visible {
        outline: 2px solid #6366f1;
        outline-offset: 2px;
    }
}

Step 3: Custom focus styles that work for everyone

.custom-button {
    background: #f0f0f0;
    border: 2px solid transparent;
    padding: 0.5rem 1rem;
    border-radius: 4px;
    cursor: pointer;
}

/* Wrong — no visible focus indicator */
.custom-button:focus {
    outline: none;
}

/* Right — subtle focus ring for all, stronger for keyboard */
.custom-button:focus-visible {
    outline: 3px solid #6366f1;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px #fff, 0 0 0 5px #6366f1;
}

Step 4: Style focus within components

/* Wrong — focus style only on the input, not the container */
.form-group input:focus-visible {
    outline: 2px solid blue;
}

/* Right — enhance the container when child has focus */
.form-group:focus-within {
    border-color: #6366f1;
    box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
}

.form-group input:focus-visible {
    outline: none; /* Remove default, rely on container */;
}

Step 5: Never use :focus { outline: none } alone

/* WRONG — this is the most common accessibility bug */
*:focus {
    outline: none;
}

/* ACCEPTABLE — only if paired with :focus-visible */
*:focus {
    outline: none;
}

*:focus-visible {
    outline: 2px solid currentColor;
}

Prevention

  • Use :focus-visible instead of :focus for keyboard focus indicators
  • Always provide a visible focus indicator — never remove it entirely
  • Use outline for focus — not box-shadow alone (outline does not affect layout)
  • Test focus with keyboard (Tab key) on every interactive element
  • Use outline-offset to separate the focus ring from the element

Common Mistakes with focus visible

  1. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  2. Non-exhaustive pattern matches that compile with warnings then crash at runtime
  3. Misunderstanding that String is [Char] with poor performance for large text operations

These mistakes appear frequently in real-world CSS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What is the difference between :focus and :focus-visible?

:focus applies whenever an element receives focus (mouse click, keyboard Tab, programmatic .focus()). :focus-visible applies only when the browser determines focus should be visible — typically keyboard navigation. Mouse clicks do not trigger :focus-visible.

Does :focus-visible work on all elements?

Yes. Every focusable element supports :focus-visible. Non-focusable elements (like <div>) do not receive focus unless they have tabindex set. Apply :focus-visible to links, buttons, inputs, and any custom interactive elements.

How does the browser decide when to show :focus-visible?

The heuristic: if the focus was triggered by a keyboard event (Tab, arrow keys), the browser shows :focus-visible. If triggered by a mouse or pointer event, it does not. Some browsers also show it after page load for elements with autofocus.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro