:focus-visible & :focus-within
Plain :focus matches any time an element has focus, regardless of how that focus was triggered — clicking with a mouse, tapping on a touchscreen, or navigating with the keyboard all count. Two more targeted pseudo-classes, :focus-visible and :focus-within, solve problems that plain :focus can't: showing a focus ring only when it is actually useful, and reacting to focus anywhere inside a container.
The old anti-pattern
/* Please don't do this */
:focus {
outline: none;
}This removes the focus indicator for EVERYONE, including keyboard users who rely entirely on that visible ring to know where they are on the page. Without it, tabbing through a form or a menu becomes effectively unusable for anyone not using a mouse.
:focus-visible — the real fix
:focus-visible matches only when the browser's own heuristic decides a focus indicator should be shown — typically keyboard navigation (Tab), and typically NOT a mouse click on a button (where the browser assumes a visible ring isn't necessary). This lets you keep default browser styling for click-focus while still styling a clear ring for keyboard focus.
/* Remove the ring only where the browser decides it isn't needed */
.button:focus {
outline: none;
}
/* But always show a clear, custom ring for keyboard focus */
.button:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}A mouse click on the button leaves it focused but without an intrusive ring; tabbing to the same button with a keyboard shows the outline clearly. This is the modern, accessible replacement for blanket outline: none.
:focus-within — style a parent when a child has focus
:focus-within matches an element if that element, OR any of its descendants, currently has focus. It's the pseudo-class equivalent of "highlight this whole container while the user is working inside it."
.form-group {
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 6px;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* Highlight the entire group when its input is focused,
not just the input itself */
.form-group:focus-within {
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}<div class="form-group"> <label for="username">Username</label> <input id="username" type="text" /> </div>
Where each one fits
:focus— the element itself has focus, no matter how it got it.:focus-visible— the element has focus AND the browser thinks a visible indicator is warranted.:focus-within— the element or ANY descendant has focus (styling a container, not the focused element itself).