# CSS :focus-visible and :focus-within: Accessible Focus Styling

Source: https://devdocs10.com/articles/css/css-focus-visible  
By Murat Bo · Published 2026-09-17 · DevDocs10 (https://devdocs10.com)

This article explains how the CSS `:focus-visible` and `:focus-within` pseudo-classes work, when to use each one, and how they help you build keyboard-friendly, accessible interfaces without over-styling mouse users.

> **Quick answer:** Use `:focus-visible` when you want a focus style to appear mainly for keyboard-like focus, and use `:focus-within` when a parent element should react because one of its descendants is focused.

> **Difficulty:** Beginner
>
> **You'll understand this better if you know:** basic CSS selectors, how focus works in forms and links, and the difference between element states like hover and active.

## 1. What Are :focus-visible and :focus-within?

The `:focus-visible` and `:focus-within` pseudo-classes let CSS respond to focus in more precise ways than plain `:focus`.

- `:focus-visible` matches an element when the browser decides the focus indicator should be shown.
- `:focus-within` matches a parent element when it or any of its descendants has focus.
- Both help make focus styling more useful and less visually noisy.

They are especially important for accessibility because keyboard users need a clear visual indicator of where focus is on the page.

## 2. Why They Matter

Focus styling is one of the easiest ways to improve keyboard accessibility. If links, buttons, and inputs do not show a clear focus state, keyboard users can get lost while tabbing through the page.

`:focus-visible` helps you avoid showing focus rings in situations where they are less helpful, such as after a mouse click in many browsers. `:focus-within` helps you style containers like form fields, menus, or cards when a child element receives focus.

That means you can design clearer interfaces without removing the browser's built-in accessibility behavior.

## 3. Basic Syntax

### Using :focus-visible

The simplest pattern is to style elements when the browser considers the focus to be visibly relevant.

```css
button:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
}
```

This rule adds a clear outline only when the browser thinks a visible focus indicator is appropriate.

### Using :focus-within

The `:focus-within` pseudo-class is often used on a container, not the focused element itself.

```css
.field:focus-within {
  border-color: #005fcc;
  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.2);
}
```

This rule changes the appearance of a wrapper whenever anything inside it is focused.

### How they differ from :focus

`:focus` matches every focused element, no matter how focus happened. That is useful, but it can be too broad if you want a more polished focus treatment.

`:focus-visible` is more selective. `:focus-within` is about a focused descendant causing a parent to match.

## 4. Step-by-Step Examples

### Example 1: Button focus ring with :focus-visible

This example styles a button so the focus ring is clear for keyboard users while avoiding unnecessary emphasis in other cases.

```css
button {
  padding: 0.75rem 1rem;
  border: 1px solid #888;
  border-radius: 0.5rem;
}

button:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 3px;
}
```

The button always keeps its normal appearance, but keyboard focus gets a strong and visible ring.

### Example 2: Input group highlighting with :focus-within

This example makes a form field wrapper react when the text input inside it is focused.

```css
.field {
  padding: 0.75rem;
  border: 1px solid #bbb;
  border-radius: 0.5rem;
}

.field:focus-within {
  border-color: #005fcc;
  background: #f7fbff;
}
```

When the input is focused, the container shows the active state, which helps users understand which group they are editing.

### Example 3: Navigation item styling

Here, `:focus-visible` gives keyboard users a clear indicator on links in a menu.

```css
nav a {
  display: inline-block;
  padding: 0.5rem 0.75rem;
  text-decoration: none;
}

nav a:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}
```

This keeps the menu clean while still meeting accessibility needs.

### Example 4: Card with a button inside

`:focus-within` is useful when the visual container should react to keyboard focus inside it.

```css
.card {
  padding: 1rem;
  border: 1px solid #ddd;
  border-radius: 0.75rem;
}

.card:focus-within {
  border-color: #005fcc;
  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.15);
}
```

The card now feels active when focus moves to the button inside it, not just when the card itself is clicked.

## 5. Practical Use Cases

- Highlighting buttons, links, and custom controls for keyboard users.
- Styling form groups when an input, select, textarea, or checkbox inside them receives focus.
- Showing active states in search bars, login forms, and settings panels.
- Making sidebar menus and navigation items easier to scan during tab navigation.
- Creating accessible composite widgets where the outer container should reflect inner focus.

## 6. Common Mistakes

### Mistake 1: Removing focus outlines without replacing them

Many beginners hide outlines because they look visually strong, but that can make keyboard navigation hard or impossible to follow.

**Problem:** This removes the browser's focus indicator and leaves keyboard users with no clear visual cue.

```css
button:focus {
  outline: none;
}
```

**Fix:** Replace the default outline with a custom focus style, ideally using `:focus-visible`.

```css
button:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
}
```

The corrected version keeps focus visible while giving you control over the design.

### Mistake 2: Expecting :focus-within to style the child element automatically

`:focus-within` matches the parent container, not the focused input itself.

**Problem:** This rule will not style the input directly, because the selector applies to `.field` instead of the nested control.

```css
.field:focus-within input {
  border-color: #005fcc;
}
```

**Fix:** Style the input itself with `:focus` or `:focus-visible`, and use `:focus-within` on the wrapper.

```css
.field:focus-within {
  border-color: #005fcc;
}

.field input:focus-visible {
  outline: none;
}
```

This works because each selector targets the element it is meant to affect.

### Mistake 3: Using :focus-visible for effects that should always appear

Not every focus style should depend on the browser's visibility heuristics.

**Problem:** If you need a state to appear whenever an element has focus, `:focus-visible` can be too narrow and may not trigger in the cases you expect.

```css
.search:focus-visible {
  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.2);
}
```

**Fix:** Use `:focus` when the visual change must appear for any focused state, or combine both selectors thoughtfully.

```css
.search:focus {
  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.2);
}
```

The corrected version ensures the focus state is visible whenever the control is focused.

## 7. Best Practices

### 1. Prefer :focus-visible for interactive controls

For buttons, links, and other keyboard-operated controls, `:focus-visible` usually gives the cleanest result because it preserves a strong indicator where it matters most.

```css
a:focus-visible,
button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}
```

This keeps the interface accessible without overemphasizing every mouse click.

### 2. Use :focus-within for grouped UI components

When a control is visually part of a larger unit, such as a search bar or a form field wrapper, `:focus-within` makes the container behave like part of the focus state.

```css
.search-box:focus-within {
  border-color: #005fcc;
  background-color: #fff;
}
```

This helps users see the active region, not just the caret inside it.

### 3. Keep focus styles visible and high contrast

Focus styles should stand out against surrounding content. A subtle color change is often not enough, especially for users with low vision or on busy backgrounds.

```css
input:focus-visible {
  outline: 3px solid #1d4ed8;
  outline-offset: 2px;
}
```

Strong contrast makes the focus location easier to recognize immediately.

## 8. Limitations and Edge Cases

- `:focus-visible` support is good in modern browsers, but older browsers may behave differently or fall back to `:focus` behavior.
- Keyboard, mouse, touch, and script-driven focus can produce different visibility results depending on browser heuristics.
- `:focus-within` can match unexpectedly deep descendants, which is useful in forms but can be surprising in complex layouts.
- Custom controls still need a real focusable element; CSS cannot make a non-focusable element receive keyboard focus by itself.
- Replacing outlines with box shadows can work well, but shadows may be clipped by overflow or blend poorly with high-contrast themes.

## 9. Practical Mini Project

Let's build a small login panel that uses both pseudo-classes together: the button and inputs get clear focus treatment, and the outer card highlights when any field inside it is active.

```html
<form class="login-card">
  <div class="field">
    <label for="email">Email</label>
    <input id="email" type="email">
  </div>

  <div class="field">
    <label for="password">Password</label>
    <input id="password" type="password">
  </div>

  <button type="submit">Sign in</button>
</form>
```

`:focus-within` works on the card and field wrappers, while `:focus-visible` works on the actual form controls.

```css
.login-card {
  max-width: 24rem;
  padding: 1.25rem;
  border: 1px solid #d1d5db;
  border-radius: 0.75rem;
}

.login-card:focus-within {
  border-color: #005fcc;
}

.field {
  margin-bottom: 1rem;
}

.field:focus-within label {
  color: #005fcc;
}

input {
  width: 100%;
  padding: 0.7rem;
  border: 1px solid #9ca3af;
  border-radius: 0.5rem;
}

input:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
}

button {
  padding: 0.75rem 1rem;
  border: 0;
  border-radius: 0.5rem;
  background: #005fcc;
  color: white;
}

button:focus-visible {
  outline: 3px solid #111827;
  outline-offset: 3px;
}
```

This small pattern scales well because each selector handles one responsibility: container focus, field grouping, and control focus.

## 10. Key Points

- `:focus-visible` is for styling elements when the browser shows a visible focus indicator.
- `:focus-within` is for styling a parent when any of its descendants receives focus.
- Use `:focus-visible` for interactive controls and `:focus-within` for grouped components.
- Never remove focus styles without replacing them with an accessible alternative.
- Good focus styling helps keyboard users navigate confidently.

## 11. Practice Exercise

Create a contact form with three fields and a submit button. Style each focused input with `:focus-visible` and make each field wrapper highlight with `:focus-within`.

- Each field should have a label, input, and wrapper.
- The wrapper should change border color when the input is focused.
- The input itself should show a visible outline when focused.

**Expected output:** Tabbing through the form clearly shows which control is focused, and the active field group is easy to identify.

**Hint:** Use one selector for the wrapper and another selector for the actual input.

```css
.contact-form {
  max-width: 32rem;
}

.field {
  margin-bottom: 1rem;
  padding: 0.75rem;
  border: 1px solid #cbd5e1;
  border-radius: 0.5rem;
}

.field:focus-within {
  border-color: #2563eb;
  background-color: #eff6ff;
}

input {
  width: 100%;
  padding: 0.65rem;
  border: 1px solid #94a3b8;
  border-radius: 0.375rem;
}

input:focus-visible {
  outline: 3px solid #2563eb;
  outline-offset: 2px;
}

button {
  padding: 0.75rem 1rem;
  border: 0;
  border-radius: 0.5rem;
  background: #2563eb;
  color: white;
}
```

## 12. Final Summary

`:focus-visible` and `:focus-within` solve different but related accessibility problems. `:focus-visible` helps you show a useful focus indicator on the element that received focus, while `:focus-within` lets a parent element reflect focus inside its subtree.

Used together, they make interfaces easier to navigate with the keyboard and easier to understand visually. They also help you avoid the common mistake of either hiding focus completely or applying focus styles too broadly.

As a next step, review the focus styles in your own forms, menus, and buttons, then replace any removed outlines with clear `:focus-visible` rules and add `:focus-within` to containers that should react as a group.

## Browser Support

| Feature | Status | Chrome | Edge | Firefox | Safari | Safari iOS |
| --- | --- | --- | --- | --- | --- | --- |
| :focus-visible | Widely available since Sep 2024 | 86+ | 86+ | 85+ | 15.4+ | 15.4+ |
| :focus-within | Widely available since Jul 2022 | 60+ | 79+ | 52+ | 10.1+ | 10.3+ |

Data: web-features 3.43.0 (MDN Baseline).
