Description
Introduction
While testing across major browsers, I observed that, in specific cases, the :focus-visible
pseudo-class matches non-interactive elements with a tabindex="-1"
attribute after pointer interaction (e.g., mouse click) followed by non-pointer interaction (e.g., keystroke).
This behavior varies between browsers, and it is unclear whether the current specification intends for :focus-visible
to match on such elements under these circumstances.
I've created a demo on CodePen to illustrate the different scenarios and behaviors.
Relevant Specification Reference
For user-agent-defined heuristics to indicate focus, the Selectors Level 4 specification provides non-normative suggestions such as:
- If the user interacts with the page via keyboard or some other non-pointing device, indicate focus. (This means keyboard usage may change whether this pseudo-class matches even if it doesn’t affect
:focus
).- If the user interacts with the page via a pointing device (mouse, touchscreen, etc.) and the focused element does not support keyboard input, don’t indicate focus.
- If the previously-focused element indicated focus, and a script causes focus to move elsewhere, indicate focus on the newly focused element.
However, the behavior for non-interactive elements defined with tabindex="-1"
, which can be focused programmatically or through pointer interaction but are not accessible by keyboard navigation, remains unclear, as reflected by the different browser implementations.
Observed Behaviors and Differences
- Non-interactive elements without
tabindex
(e.g.,<section>
)- Cannot receive focus.
- No issues observed, expected behavior.
- Non-interactive elements with
tabindex="0"
(e.g.,<section tabindex="0">
)- Focusable by pointer interaction (e.g., mouse click) and non-pointer interaction (e.g., keyboard tabbing).
- After pointer interaction (
:focus
via mouse click), a specific non-pointer interaction (e.g., keystroke) triggers:focus-visible
in Chrome and Safari, but not in Firefox.
- Non-interactive elements with
tabindex="-1"
(e.g.,<section tabindex="-1">
)- Focusable via script or pointer interaction, but not via keyboard navigation.
- The same behavior occurs as with
tabindex="0"
. - It remains unclear whether this behavior is intended, since
tabindex="-1"
elements are not keyboard-focusable.
- Interactive and focusable child elements within
tabindex="-1"
elements (e.g.,<section tabindex="-1">
containing a<button>
)- Interaction with a focusable child element (e.g.,
<a>
,<button>
, or<input type="checkbox">
) behaves differently across browsers:- Firefox: The child element receives
:focus
on pointer interaction (click), but does not change to:focus-visible
on non-pointer interaction (key activation). - Chrome: Non-pointer interaction (key activation) after pointer interaction (click) triggers
:focus-visible
on the child element. - Safari (platform-dependent): The parent with
tabindex="-1"
receives:focus
instead of the child element on pointer interaction (click).
- Firefox: The child element receives
- Interaction with a text input element (e.g.,
<input type="text">
)- Consistent and expected behavior across Chrome, Safari, and Firefox:
:focus-visible
appears after both pointer and non-pointer interaction because the element awaits keyboard input.
- Consistent and expected behavior across Chrome, Safari, and Firefox:
- Programmatic focus on the parent element (
<section tabindex="-1">
) via button (<button type="button">
) activation:- Consistent and expected behavior across Chrome, Safari, and Firefox (in line with spec suggestions): On pointer interaction (click), the parent element receives
:focus
; on non-pointer activation (keyboard), it receives:focus-visible
.
- Consistent and expected behavior across Chrome, Safari, and Firefox (in line with spec suggestions): On pointer interaction (click), the parent element receives
- Interaction with a focusable child element (e.g.,
- Keystroke exceptions
- Modifier keys (e.g., fn, Control, Option/Alt, Command) and function keys (e.g., F1–F12) generally do not trigger
:focus-visible
when an element is already focused (:focus
). - Safari differs slightly: Pressing the Shift key does not trigger
:focus-visible
, while in Chrome it does.
- Modifier keys (e.g., fn, Control, Option/Alt, Command) and function keys (e.g., F1–F12) generally do not trigger
I am not claiming that any particular behavior is incorrect. I am seeking clarification to ensure consistent behavior across user agents.
Further Resources
- WebKit Bugzilla 225148: [selectors] :focus-visible and keyboard events — related discussion about
:focus-visible
behavior and keyboard events - Mozilla Bugzilla 1688539: New wpt failures in /css/selectors/focus-visible-007.html — related discussion on WPT failures for
:focus-visible
and keyboard interaction