Accessibility

Simplified WCAG guidelines

WCAG 2.2 – Levels A and AA only, with dev notes.

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
Normal link
Details / summary

Exposed details.

Legend
Radio buttons:
Content editable div

Focus ring - CSS required

Exposed custom properties (CSS variables) for both versions
Focus ring CSS exposed custom properies
/* 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
Focus ring CSS (production)
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

Focus ring CSS (latest browsers)
: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);
}