Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[focusgroup] Proposal: drop the limitation of focusgroup applying to children-only #989

Closed
travisleithead opened this issue Feb 8, 2024 · 9 comments

Comments

@travisleithead
Copy link
Collaborator

In the explainer today, focusgroup elements cause all of their direct-children to become focusgroup candidates, but that's it. If there are some other potential focusgroup candidates that are not direct-children, but the author would like them to be included in the original focusgroup, the extend feature provides a way to extend the parent's focusgroup to some descendant set of children.

I've started to take a look at the various patterns in the ARIA Authoring Practices Guide and the examples for Accordion and Tree View in an attempt to see how focusgroup would work in practice in those examples. In 2 of the 3 examples for Tree View, authors would end-up needing lots of redundant focusgroup definitions, just to ensure children are properly hooked up to ancestor focusgroup definitions. Similar story for the Accordion example (though it doesn't make use of optional keyup/down behaviors that are described in the Keyboard Interaction section). In just these few examples, it seems apparent that use of focusgroups as currently described will be annoying to authors in a lot of cases.

Given that, and the support expressed for dropping the children-only requirement expressed on the Discord focusgroup channel, I'd like to propose that this requirement be removed. In other words, use of a focusgroup attribute would setup a scope for all children and descendants of the focusgroup-declaring element to be focusgroup candidates.

If we decide to make this change, there are a couple of other changes that fall-out as a result:

  1. It becomes more important to have an opt-out mechanism since many more elements will be automatically added as focusgroup candidates. (The current proposal describes an opt-out mechanism for individual elements, but it requires CSS only and is considered an edge case.)
  2. The various use cases for extend are reduced to just one case: flipping the orthogonality of a linear focusgroup (and potentially changing the wrapping behavior).

I like the simplification, and I really like how it reduces the complexity of focusgroup, and seems to increase the developer ease-of-use.

Note: in the below proposals, the element declaring the focusgroup is not a member of the focusgroup (this is the current explainer POV). With this change, we could re-evaluate whether the element declaring the focusgroup will become a part of the focusgroup itself. This could make more sense given the opt-out proposals.

Part 1: linear focusgroup declarations apply to an element's subtree (not just children only)

No change to existing syntax, this just expands the scope of a focusgroup declaration:

<form focusgroup>
  <!-- all children and descendants (this whole subtree) is now part of the focusgroup -->
</form>

Part 2: focusgroup subtree opt-out

With such a generous default opt-in behavior, we should provide a way to opt-out a subtree just as easily. focusgroup=none.

<div focusgroup>
  <div>
    <div>
      <div focusgroup="none"> <!-- this subtree (this div's children and descendants) are excluded from the focusgroup -->
      </div>
    </div>
  </div>
</div>

Part 3: focusgroup individual element opt-out

Individual elements may want to opt-out of focusgroup participation (allowing their children and sub-tree to continue to be opted-in). This is described in the explainer today, but requires CSS (focus-group-item: none).

Note: I'm having a hard time thinking of a use-case for this in which the element opting-out is not a leaf-node in the tree and wants its descendants to still participate. If no one else can think of a use case either, maybe this scenario can be dropped, especially if we change the above meaning of the focusgroup=none declaration to apply to the declaring element and its subtree.

Part 4: drop the extend concept

There is no need to extend focusgroups anymore when they automatically include the whole subtree. However, there is still a use-case to be able to switch the directionality of a linear focusgroup when it was constrained in one direction in an ancestor to be the opposite direction. In the current explainer text, authors can chose to make weird combinations of directionality such that arrow-key movement becomes non-bi-directional. From the current explainer:

The arrow key interactions will be clearer to users when nested focusgroups are strictly orthogonal to each other. Authors should not extend both direction linear focusgroups with single-directional linear focusgroups (and vice-versa) as a best practice.

We have an opportunity to remove this foot-gun and help ensure a good user experience for these cases. Instead of extend we replace it with orthogonal which means:

  • if there is an ancestor focusgroup in scope
    • if that ancestor focusgroup was limited in directionality to either horizontal or vertical
      • swap the limited directionality for this element's subtree (and potentially apply a new wrapping behavior).

If any of the 'if' conditions fail, then... (reasonable fallback behavior, which could be to treat the orthogonal token as if it was omitted)

<div focusgroup=horizontal>
  <div>
    <div>
      <div focusgroup=orthogonal> <!-- this subtree responds to vertical-direction arrow keys only-->
      </div>
    </div>
  </div>
</div>

This avoids a lot of potential developer pitfalls by dramatically limiting the previous expressive power of extend to just the use-case that remains.

In these scenarios where direction changes, I would like to propose a simpler way for how the focusgroup will determine what arrow keys to accept. From a given focusable element, a forward-direction arrow key (of either horizontal or vertical arrow keys) finds the next focusable element in DOM order whose focusgroup supports that direction (skipping orthogonal focusgroup subtrees where the direction doesn't match). This is a partial fix for the current explainer's example 12.

@travisleithead
Copy link
Collaborator Author

And after noodling more on this, I think that we need to revisit the notion that the element that declares a focusgroup does not participate in it.

⭐ Note: in the below proposals, the element declaring the focusgroup is not a member of the focusgroup (this is the current explainer POV). With this change, we could re-evaluate whether the element declaring the focusgroup will become a part of the focusgroup itself. This could make more sense given the opt-out proposals.

By having the declaring element also be a part of the focusgroup, then we can eliminate the "Part 3" case above, "Part 2" handles both the case of opting out an individual element AND its subtree. I assert that in most cases, the containing element for a focusgroup won't itself be focusable, and if it is, then it would still make sense for it to be a part of the focusgroup it declares. Would love to hear some counter-examples to this.

@travisleithead travisleithead added the agenda+ Use this label if you'd like the topic to be added to the meeting agenda label Feb 21, 2024
@travisleithead travisleithead removed the agenda+ Use this label if you'd like the topic to be added to the meeting agenda label Mar 5, 2024
@travisleithead
Copy link
Collaborator Author

I've been looking at real-world use cases for when "Part 4" above might be useful (the "orthogonal" use-case), and in nearly every scenario I've found (menus, toolbars, tabs, etc. [combing through various accessibility control patterns]) there is little need to have the feature. Why? Because the cross-action arrow key behavior in most cases requires script to do some additional processing (like reveal/hide menus, redirect focus, activate control surface, etc.) and that is processing that will require responding to the arrow key press events manually--therefore those cases wouldn't rely on default cross-action arrow key actions provided by the focusgroup feature (for descent/ascent).

For example, consider the menubar and submenus in Google Docs. The menubar could easily add a focusgroup=inline to handle the arrow key movement between menubar items. The menus couldn't be a cross-axis focusgroup because their activation requires (1) revealing the submenu--script needed right now since we don't have invokers yet, (2) cross action arrow keys in both directions activate the submenu (this was not planned for the "part 4" feature), and movement out of the menu and back to the menubar varies depending on the particular menu (so, driven by script customizations)--for example, when focused on the Format>Text>Bold menu, a cross-action right arrow key moves to the next menu "Tools" and opens the Tools menu (without focusing it). However, when focused on the Format>Bullets and Numbering>Checklist menu>submenu, the right arrow key is trapped (wraps around in the submenu). Google Docs could still use focusgroup, but they would probably use independent focusgroups with specific axis limitations and then re-use their custom scripts on the cross-axis arrow keys to preserve existing behavior within the individual menubar, menus, and submenus.

Unless we go down the road of encoding the expected default behavior for cross-axis menus of a control pattern within a focusgroup, e.g., focusgroup=menubar, (and similar for other patterns), it's likely that web devs will continue to just implement whatever they need/want in their control pattern on the cross-axis arrow key directions in script (hopefully per APG guidance). So, there's no single compelling use case to continue to try to spec "Part 4" if it won't get much use. I'm proposing dropping that part of the feature.

@lukewarlow
Copy link
Collaborator

revealing the submenu--script needed right now since we don't have invokers yet.

While this is true, we will have invokers soonish and hopefully interest invokers (focus triggered) not too long into the future. I wouldn't want to limit focus group based on a limitation that is actively being solved.

That being said I'm not sure if the feature that you talk about is necessary or not. Just want to make sure we keep or drop it for the right reasons.

@css-meeting-bot
Copy link

The Open UI Community Group just discussed [focusgroup] Proposal: drop the limitation of focusgroup applying to children-only, and agreed to the following:

  • RESOLVED: drop the focusgroup's single-children requirement and related changes
The full IRC log of that discussion <Penny> Travis: We have a couple of developer experience improvements to make, one of them is that focusgroup the attribute only ops in it's direct children, then additional steps are needed to extend the ancestor focusgroup down to other descendent parts of the subtree which is clunky. In a lot of examples we looked at, to implement custom controls, it will almost work but there will be part of the tree that is deeper than one child level below where
<Penny> we'd want to put a focusgroup. The original reason for the limitation was that in CSS if an element was going to be declared display grid or flex it was going to apply only to those children, and focusgroup seemed like that, but now seems less so.
<Penny> Travis: proposal to remove that limitation, so subtree will be added, but that might be unexpected. So we would allow an opt out ex. focusgroup=none
<argyle> a demo with nested focusable items in a focus group https://gui-challenges.web.app/media-scroller/dist/
<masonf> q?
<masonf> q+
<Penny> Travis: proposal to remove that limitation, so subtree will be added, but that might be unexpected. So we would allow an opt out ex. focusgroup=none
<Penny> Travis: when focusgroup starts to apply to a subtree we can start to remove features, which is good, extend feature becomes no longer necessary
<Penny> Travis: A large portion of explainer dedicated to linking up direction of focusgroups and have it automatically ascend/descend, on reflection it has not seemed like there is a clear developer use case for this
<keithamus> q+
<Penny> Travis: Expect to scratch this entire feature which would remove a significant part of the explainer
<Penny> Travis: Grid focus group work with table, grids are tricky though, can have overlapping grid cells, and other complicated scenarios. I might write this up as an experimental part of the explainer
<Penny> @masonf: seems good, easier to understand, good developer experienec
<Penny> masonf: seems good, easier to understand, good developer experienec
<masonf> ack mason
<masonf> ack keith
<Penny> keithamus: if you have a toolbar of button and one is a "more" button, and toolbar is a focusgroup, if you push right to get to that button and then down, is this a use case?
<masonf> q?
<Travis> PROPOSED RESOLUTION: drop the focusgroup's single-children requirement and related changes
<keithamus> +1
<philippg> +1
<dandclark> +1
<Travis> RESOLVED: drop the focusgroup's single-children requirement and related changes
<dbaron> +1
<argyle> +1

@gfellerph
Copy link
Contributor

@travisleithead would you see the following mega dropdown menu as a good use of focusgroup (for the links of the main and sub-navigation)?

Screenshot of the header of the Swiss Post home page with the megadropdown expanded

When tabbing through this menu right now (https://post.ch), focus goes from the first main navigation entry through the whole subnavigation links before it reaches the second main navigation entry. I'm not saying this is the best solution, but the other alternative would be to go trough all the main nav entries first and then reach the subnavigation which kind of disconnects the subnavigation from the currently open main nav entry.

With a focusgroup, users could choose between quickly going through the main navigation entries or diving down into subnavigation entries. I don't know how users would discover that this feature even exists (as Scott already mentioned), but to me, this would be a use-case where orthagonal axis focusgroups would be helpful.

<main-navigation focusgroup=horizontal>
  <a href="">Sending letters</a>
  <sub-navigation>
    <nav-column focusgroup=vertical>
      <a href="">Domestic letters</a>
    </nav-column>
    <nav-column focusgroup=vertical>
      <a href="">Franking mail</a>
    </nav-column>
  </sub-navigation>
  <a href="">Sending parcels</a>
</main-navigation>

On the other hand, maybe focusgroup=grid would make more sense here, since it's not entirely clear to me if, when focusing a subnavigation link in column one, a right arrow key press would jump focus to the second main navigation entry or the second subnavigation column, first link.

@travisleithead
Copy link
Collaborator Author

Yes, I think a focusgroup could help make this navigation easier, but it would need to be modeled with the right pattern. (Of course, I'd like to see a focusgroup used everywhere, but I'm biased... 😉)

That use case looks to me like tabs with each tab-panel filled with a list of links. Tabs might be the right top-level pattern to use (and focusgroup will help with the tablist). Then, you could model the big list of links in each tabpanel with another pattern. The lists of links could also be modeled as tabs (a tablist inside a tabpanel where the sub-tabpanels are always visible and don't need to be activated?) I can think of some other patterns that might work for that use case and would also set appropriate accessible expectations... here's three:

  1. Model the grouped set of links as a layout grid - see Layout Grid example on APG.
    • use focusgroup=grid
    • This would provide 2d navigation, but may not make a lot of sense if the columns aren't all balanced.
  2. Model the grouped set of links as a menubar with menus that are always expanded out - see Navigational Menubar example on APG.
    • Use nested single-axis linear focusgroups (I think this is what you were getting at above...) JS will be needed on the cross-axis directions to ascend/descend into each focusgroup after we remove automatic ascend/descend from the spec)
    • Gives top-level category navigation, but might set the expectation that the menus can be expanded/collapsed.
  3. Model the grouped set of links as a non-interactive expanded tree view - see Tree View example on APG.
    • This would allow arrow keys in one direction to "flow" through the entire list (wrapping from the bottom of one column to the header of the next), but would require JS to provide the header-to-header (e.g., "Services" <-> "Step by step" <-> "Please note for") navigation.

The grid pattern (1) would be the easiest and not require any JS for the best experience. I'd specify focusgroup=grid col-flow so that the user can just press "down arrow" to move through the whole grid, wrapping from column to column at the column ends.

I'm not actually sure how you communicate "non-interactive" in ARIA for the menus... aria-readonly=true?

@gfellerph
Copy link
Contributor

@travisleithead thank you for the in-depth answer, that clears up a lot of things. Also an interesting take away from the APG Layout Grid example for arrow key affordance:
image

  • A dotted focus border
  • An arrow button graphic appearing in a corner of the screen (does not seem to work in the example on Chrome though)

@travisleithead
Copy link
Collaborator Author

That's interesting, and a good recommendation for how to present the focus indicator when in a focusgroup--it's subtle, but could become a best-practice and/or get baked into the default stylesheet of UAs. That would be pretty cool!

travisleithead added a commit that referenced this issue Mar 28, 2024
First revision relative to addressing issues #537 and #989:

## Sections updated (and attempts at simplification):
   * introduction.
   * goals
   * non-goals
   * principles
   * use cases: drop extend, drop multiple focusgroups on one node.
   * focusgroup concepts
   * wrapping
   * axis-limiting
   * opt-out
   * grid updates

## Sections removed:
   * 'extend' concept and orthogonal focusgroups
   * multiple focusgroups for siblings

## Sections added:
   * disabling focusgroup memory
   * sequential focus navigation algorithm updates
   * feature detection
   * design decisions

## General document hygiene:
   * Adding a quickstart section
   * Remove numbers from headers

***Make this an Active explainer again.***
@travisleithead
Copy link
Collaborator Author

OK, PR #1021 has landed with these changes. It's a major re-write, so might be worth reading the explainer again top-to-bottom. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants