- From: ivan via GitHub <sysbot+gh@w3.org>
- Date: Sat, 26 Apr 2025 19:37:24 +0000
- To: public-css-archive@w3.org
glmvc has just created a new issue for https://github.com/w3c/csswg-drafts:
== [selectors] :focus-visible matching heuristic unclear for non-interactive elements with tabindex="-1" ==
## 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](https://codepen.io/glmvc/full/VYYmgdG).
## Relevant Specification Reference
For user-agent-defined heuristics to [indicate focus](https://drafts.csswg.org/selectors/#indicate-focus), the [Selectors Level 4 specification](https://drafts.csswg.org/selectors/#the-focus-visible-pseudo) 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`](https://drafts.csswg.org/selectors/#focus-pseudo)).
> - 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
1. Non-interactive elements _without_ `tabindex` (e.g., `<section>`)
- _Cannot_ receive focus.
- **No issues** observed, **expected behavior**.
2. 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.
3. 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**.
4. 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).
- 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**.
- 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`.
5. 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.
> 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](https://bugs.webkit.org/show_bug.cgi?id=225148) — related discussion about `:focus-visible` behavior and keyboard events
- [Mozilla Bugzilla 1688539: New wpt failures in /css/selectors/focus-visible-007.html](https://bugzilla.mozilla.org/show_bug.cgi?id=1688539) — related discussion on WPT failures for `:focus-visible` and keyboard interaction
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12127 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Saturday, 26 April 2025 19:37:25 UTC