html icon indicating copy to clipboard operation
html copied to clipboard

[focusgroup] Declarative keyboard focus navigation for a scoped set of composite widgets

Open janewman opened this issue 3 months ago • 7 comments

What problem are you trying to solve?

Authors routinely hand-code “roving tabindex” logic for composite widgets like toolbars, tablists, menus, listboxes, and grids. In practice, this means providing a single tab stop to enter the control, then using arrow keys to move focus between items.

This ad‑hoc scripting:

  • Produces inconsistent keyboard behavior across sites.
  • Increases accessibility risk; missed ARIA roles, incorrect tabindex management, broken tab order.
  • Adds boilerplate and maintenance burden in every design system and framework.

What solutions exist today?

  • Hand-authored JS roving tabindex patterns (MDN-documented technique) duplicated per project.
  • Library abstractions (e.g., FocusZone (Fluent UI), Tabster, react-aria, react-roving-tabindex, a11y utilities in multiple frameworks).

How would you solve it?

Introduce a focusgroup HTML attribute with scoped behavior tokens for recognized composite patterns plus optional modifiers (axis limits, wrap, memory control, opt‑out), providing native arrow-key focus movement, a guaranteed entry tab stop, and last-focused restoration. Explainer in OpenUI

Anything else?

A previous, unscoped version of this attribute was brought up years ago, but was blocked on accessibility issues. This "Scoped Focusgroup" feature limits usage to a set of behaviors that can supply a minimum aria role when needed, ensuring compatibility with ATs by-default.

Draft Specification PR

https://github.com/whatwg/html/pull/11723

janewman avatar Sep 08 '25 20:09 janewman

Arrow key events control normally scrolling. The explainer doesn't seem to mention scrolling at all. Which would get higher priority, focus navigation or scrolling? I assume focus navigation, but how does that exactly work? What if there is scrollable area inside the focus group?

smaug---- avatar Sep 19 '25 00:09 smaug----

I've been following the proposal for a while and this would be my understanding of scroll handling: During regular arrow key navigation inside a focusgroup, I would expect the same behaviour as during tab navigation. If the next focusgroup candidate is outside of the viewport and in a scrollable area, the browser scrolls the focused element into view. If a focusgroup does not have the wrap option, up/down arrows will start to scroll once the first/last focusgroup element is reached because the focusgroup is no longer handling the keypress. Same for left and right arrow keys with sideways scrolling.

I'm not sure if scrollable areas are now focusable in all browsers (@lukewarlow do you know?), but they would count as key conflicting elements and be handled accordingly. Similar to how text input fields are handled. There is an ongoing discussion about what exactly that means here: https://github.com/openui/open-ui/issues/1281.

@janewman what do you think?

gfellerph avatar Sep 19 '25 21:09 gfellerph

WebKit doesn't (yet?) support scrollable areas becoming automatically focusable. But chromium and firefox do (though I think they differ slightly in their exact heuristics)

lukewarlow avatar Sep 19 '25 21:09 lukewarlow

Noting related issue: https://github.com/openui/open-ui/issues/1008

I'll add a section on how this interacts with scrolling to the explainer soon, but here are my general thoughts, let me know your thoughts.

First, I'll break this down into two situations, as I think they are fairly distinct.

1) Focusgroup in within a scrollable region

This is probably the most common situation, all you need is a focusgroup within a page that scrolls.

a. For focusgroups that wrap: Focus navigation will take priority. Scrolling will only occur as-needed to ensure the focused content is visible, similar to how it does for tab navigation. b. For focusgroups that do not wrap: Focus navigation will take priority, but once the focus has reached a boundary (start/end) arrowing past will allow for scrolling.

If in a focusgroup that restricts arrow keys to a specific axis (inline or block) then the cross axis arrow keys will still allow scrolling.

2) Scrollable region within a focusgroup

a. If in a focusgroup that restricts arrow keys to a specific axis (inline or block) then the cross axis arrow keys will allow scrolling, assuming the scrollable region is only scrollable in the cross axis of the focusgroup. b. If there is a conflict, then this scrollable region should be considered a "key conflict element" @gfellerph and I have been discussing this in issue #1281

Examples of this or similar behavior:

janewman avatar Sep 19 '25 21:09 janewman

/sub going to be watching this!

i'm one of the dorks with an implementation out there 😅

argyleink avatar Sep 25 '25 21:09 argyleink

We would like to discuss moving this to stage 2 (iteration) Entry Criteria for stage 2:

  • [x] A draft specification for the Contribution: https://github.com/whatwg/html/pull/11723
  • [ ] Consensus that the rough API shape defined in the draft specification is the right approach to solve the problem.: Added this issue to agenda to discuss this point

janewman avatar Oct 07 '25 23:10 janewman

Draft spec PR

leotlee avatar Dec 02 '25 23:12 leotlee