How to change the focus outline
Short answer
Set your own outline in the :focus-visible pseudo-class. Press Tab to see it:
<style>
button, a { outline: none; }
button:focus-visible, a:focus-visible { outline: 3px solid orange; outline-offset: 3px; border-radius: 4px; }
</style>
<button>Save</button>
<a href="#">Help</a>:focus-visible fires when focus should be shown — when moving with the keyboard. A mouse click on the button shows no outline, while a text field always shows it.
Why outline and not border
outline takes no space and does not shift neighboring elements, and outline-offset moves the outline away from the edge. A border changes the element size, and everything around twitches slightly on focus.
Highlighting the whole card
If a card contains a field or a link, the :focus-within pseudo-class or :has(:focus-visible) highlights the whole block:
<style>
.card { padding: 12px; border: 2px solid silver; border-radius: 8px; }
.card:has(:focus-visible) { border-color: steelblue; }
</style>
<div class="card"><a href="#">Read the article</a></div>Common mistake
:focus { outline: none; } is written with no replacement. A visitor who does not use a mouse no longer sees where they are on the page. Remove the default outline only together with a clear one of your own.
Functions used in this recipe
- :focus-visible — Matches a focused element when the browser decides the focus should be visible — usually after keyboard navigation.
- :focus — Matches the element that currently has focus: a field being typed into, a button selected with Tab.
- outline — An outline around the element that takes no space and does not shift neighbors.
- :has() — Matches an element that contains something matching the selector in brackets — the "parent selector".