Focusable elements - focus ring enhancements
Enhancing the keyboard focus ring.
Keyboard testing
Use the keyboard TAB key to navigate through the test elements.
Uses :focus-visible
where supported and falls back to :focus
where not.
Focusable elements for testing
Focus ring - CSS required
Exposed custom properties (CSS variables) for both versions
/* Optional: override the defaults */
body {
--FocusRing-outline-color: blue;
--FocusRing-outline-width: 2px;
--FocusRing-outline-offset: 2px;
--FocusRing-transition-offset: 5px;
}
/* Required for focus animation */
@media (prefers-reduced-motion: no-preference) {
body {
--FocusRing-transition-duration: 0.3s;
}
}
Focus ring CSS - Production version
a,
button,
summary,
[tabindex],
input,
select,
textarea,
[contenteditable] {
outline: var(--FocusRing-outline-width, 2px) solid transparent;
outline-offset: var(--FocusRing-transition-offset, 5px);
transition: outline-offset var(--FocusRing-transition-duration, 0) ease-out;
}
a:focus,
button:focus,
summary:focus,
[tabindex]:focus,
input:focus,
select:focus,
textarea:focus,
[contenteditable]:focus {
outline-color: var(--FocusRing-outline-color, blue);
outline-offset: var(--FocusRing-outline-offset, 2px);
}
@supports selector(:focus-visible) {
a:focus:not(:focus-visible),
button:focus:not(:focus-visible),
summary:focus:not(:focus-visible),
[tabindex]:focus:not(:focus-visible),
input:focus:not(:focus-visible),
select:focus:not(:focus-visible),
textarea:focus:not(:focus-visible),
[contenteditable]:focus:not(:focus-visible) {
outline: none;
}
}
:focus-visible {
outline-color: var(--FocusRing-outline-color, blue);
outline-offset: var(--FocusRing-outline-offset, 2px);
}
Much cleaner CSS if your supported browser matrix supports :is()
Focus ring CSS - (latest browsers)
Supported browsers: Chrome 88, Edge 88, Safari 15.1, Firefox 78, Opera 75, Safari iOS 14, Samsung 15, Opera mobile 15, Android 105
:is(a[href], button, summary, [tabindex], input, select, textarea, [contenteditable]) {
outline: var(--FocusRing-outline-width, 2px) solid transparent;
outline-offset: var(--FocusRing-transition-offset, 5px);
transition: outline-offset var(--FocusRing-transition-duration, 0) ease-out;
}
:is(a[href], button, summary, [tabindex], input, select, textarea, [contenteditable]):focus {
outline-color: var(--FocusRing-outline-color, blue);
outline-offset: var(--FocusRing-outline-offset, 2px);
}
@supports selector(:focus-visible) {
:is(a[href], button, summary, [tabindex], input, select, textarea, [contenteditable]):focus:not(:focus-visible) {
outline: none;
}
}
:focus-visible {
outline-color: var(--FocusRing-outline-color, blue);
outline-offset: var(--FocusRing-outline-offset, 2px);
}