When you move through links, buttons, and form fields with a keyboard, a visible focus style helps you see what you’re about to use. The CSS pseudo-class :focus-visible lets you style that state without showing the same focus treatment during mouse interaction. Unlike :focus, it does not apply simply because a mouse click focused an element. section 10.9.1 section 1.6.3
Start with a profile card
Suppose a card ends with a message link and a follow button. Style both as actions, then add `*:focus-visible { outline: dotted 1px var(--primary); outline-offset: 3px; }`. The universal selector gives keyboard navigation a consistent dotted indicator across the card; the offset separates it from the focused element. section 6.8
Listing 6.21 Adding flex-wrap
.actions a, .actions button { #1
padding: 12px 24px;
border-radius: 4px;
text-decoration: none; #2
border: solid 1px var(--primary);
font-size: 1rem;
cursor: pointer;
}
.follow {
background: var(--primary);
color: var(--primary-contrast);
}
.message {
background: var(--primary-contrast);
color: var(--primary);
}
*:focus-visible {
outline: dotted 1px var(--primary);
outline-offset: 3px;
}
The listing places the shared focus rule after the individual link and button styles, so the two actions keep their different colors but receive the same keyboard-focus indicator. section 6.8
A form may need different indicators for different controls. Text fields, a drop-down menu, and a text area can use a dashed bottom border instead of their default outline. Radio buttons and check boxes can retain an outline, changing it to a dashed line with a small offset. If an invalid field already has a red error border, keep that color when it gains keyboard focus. The change in border style also means focus is not communicated by color alone. section 10.9.1 section 10.11
Listing 10.22 Styling text fields and drop-down menu when focused
:is(
input:not([type="radio"], [type="checkbox"]),
textarea,
select
):focus-visible {
outline: none; #1
border-bottom: dashed 1px var(--primary);
border-image: none; #2
}
:is( #3
input:not([type="radio"], [type="checkbox"]).dirty:invalid, #3
textarea.dirty:invalid, #3
select.dirty:invalid #3
):focus-visible { #3
border-color: var(--error); #3
} #3
The form listing groups text-like controls with `:is(...):focus-visible`, then adds a separate rule to preserve the error-border color on dirty, invalid controls. section 10.9.1
Coordinate hover and keyboard focus
A share button can use `:hover` and `:focus-visible` in one rule to show a solid outline for either interaction. An `outline-offset` of `-5px` places that outline inside the button; a positive offset would move it outward. section 11.5.1
